[maven-scm] copy for tag apache-mime4j-0.6.1

git-svn-id: https://svn.apache.org/repos/asf/james/mime4j/tags/apache-mime4j-0.6.1@1053175 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/apache-mime4j-0.6/BUILDING.txt b/apache-mime4j-0.6/BUILDING.txt
new file mode 100644
index 0000000..1d1c3a9
--- /dev/null
+++ b/apache-mime4j-0.6/BUILDING.txt
@@ -0,0 +1,44 @@
+Building Apache Mime4j 

+======================

+

+(1) Requisites

+--------------

+Mime4j utilizes Maven 2 as a distribution management and packaging tool. Version 2.0.7 

+or above is recommended. 

+

+JDK 1.5 or above is required in order to compile Mime4j.

+

+Maven installation and configuration instructions can be found here:

+

+http://maven.apache.org/run-maven/index.html

+

+(2) Executing test cases

+

+Execute the following command in order to compile and test the components:

+

+mvn test

+

+(3) Building packages 

+

+Execute the following command in order to build JAR and assembly packages:

+

+mvn package

+

+One can also utilize the 'local' profile to build JAR and assembly packages

+in the off-line mode:

+

+mvn -Plocal package

+

+Redistributables will be placed in the target folder. 

+

+(4) Building documentation 

+

+Execute the following command in order to generate javadoc:

+

+mvn javadoc:javadoc

+

+(5) Building project web site 

+

+Execute the following command in order to generate the project web site:

+

+mvn site
\ No newline at end of file
diff --git a/apache-mime4j-0.6/LICENSE.txt b/apache-mime4j-0.6/LICENSE.txt
new file mode 100644
index 0000000..2fbf3a1
--- /dev/null
+++ b/apache-mime4j-0.6/LICENSE.txt
@@ -0,0 +1,451 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+   
+   
+   
+
+   THIS PRODUCT ALSO INCLUDES THIRD PARTY SOFTWARE REDISTRIBUTED UNDER THE
+   FOLLOWING LICENSES:
+
+   JUnit, Common Public License Version 1.0  (junit-3.8.1.jar)
+     http://junit.org
+		
+		THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC
+		LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+		CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+		
+		1. DEFINITIONS
+		
+		"Contribution" means:
+		
+		a) in the case of the initial Contributor, the initial code and
+		documentation distributed under this Agreement, and
+		
+		b) in the case of each subsequent Contributor:
+		
+		i) changes to the Program, and
+		
+		ii) additions to the Program;
+		
+		where such changes and/or additions to the Program originate from and are
+		distributed by that particular Contributor. A Contribution 'originates' from a
+		Contributor if it was added to the Program by such Contributor itself or anyone
+		acting on such Contributor's behalf. Contributions do not include additions to
+		the Program which: (i) are separate modules of software distributed in
+		conjunction with the Program under their own license agreement, and (ii) are not
+		derivative works of the Program.
+		
+		"Contributor" means any person or entity that distributes the Program.
+		
+		"Licensed Patents " mean patent claims licensable by a Contributor which are
+		necessarily infringed by the use or sale of its Contribution alone or when
+		combined with the Program.
+		
+		"Program" means the Contributions distributed in accordance with this Agreement.
+		
+		"Recipient" means anyone who receives the Program under this Agreement,
+		including all Contributors.
+		
+		2. GRANT OF RIGHTS
+		
+		a) Subject to the terms of this Agreement, each Contributor hereby grants
+		Recipient a non-exclusive, worldwide, royalty-free copyright license to
+		reproduce, prepare derivative works of, publicly display, publicly perform,
+		distribute and sublicense the Contribution of such Contributor, if any, and such
+		derivative works, in source code and object code form.
+		
+		b) Subject to the terms of this Agreement, each Contributor hereby grants
+		Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed
+		Patents to make, use, sell, offer to sell, import and otherwise transfer the
+		Contribution of such Contributor, if any, in source code and object code form.
+		This patent license shall apply to the combination of the Contribution and the
+		Program if, at the time the Contribution is added by the Contributor, such
+		addition of the Contribution causes such combination to be covered by the
+		Licensed Patents. The patent license shall not apply to any other combinations
+		which include the Contribution. No hardware per se is licensed hereunder.
+		
+		c) Recipient understands that although each Contributor grants the licenses
+		to its Contributions set forth herein, no assurances are provided by any
+		Contributor that the Program does not infringe the patent or other intellectual
+		property rights of any other entity. Each Contributor disclaims any liability to
+		Recipient for claims brought by any other entity based on infringement of
+		intellectual property rights or otherwise. As a condition to exercising the
+		rights and licenses granted hereunder, each Recipient hereby assumes sole
+		responsibility to secure any other intellectual property rights needed, if any.
+		For example, if a third party patent license is required to allow Recipient to
+		distribute the Program, it is Recipient's responsibility to acquire that license
+		before distributing the Program.
+		
+		d) Each Contributor represents that to its knowledge it has sufficient
+		copyright rights in its Contribution, if any, to grant the copyright license set
+		forth in this Agreement.
+		
+		3. REQUIREMENTS
+		
+		A Contributor may choose to distribute the Program in object code form under its
+		own license agreement, provided that:
+		
+		a) it complies with the terms and conditions of this Agreement; and
+		
+		b) its license agreement:
+		
+		i) effectively disclaims on behalf of all Contributors all warranties and
+		conditions, express and implied, including warranties or conditions of title and
+		non-infringement, and implied warranties or conditions of merchantability and
+		fitness for a particular purpose;
+		
+		ii) effectively excludes on behalf of all Contributors all liability for
+		damages, including direct, indirect, special, incidental and consequential
+		damages, such as lost profits;
+		
+		iii) states that any provisions which differ from this Agreement are offered
+		by that Contributor alone and not by any other party; and
+		
+		iv) states that source code for the Program is available from such
+		Contributor, and informs licensees how to obtain it in a reasonable manner on or
+		through a medium customarily used for software exchange.
+		
+		When the Program is made available in source code form:
+		
+		a) it must be made available under this Agreement; and
+		
+		b) a copy of this Agreement must be included with each copy of the Program.
+		
+		Contributors may not remove or alter any copyright notices contained within the
+		Program.
+		
+		Each Contributor must identify itself as the originator of its Contribution, if
+		any, in a manner that reasonably allows subsequent Recipients to identify the
+		originator of the Contribution.
+		
+		4. COMMERCIAL DISTRIBUTION
+		
+		Commercial distributors of software may accept certain responsibilities with
+		respect to end users, business partners and the like. While this license is
+		intended to facilitate the commercial use of the Program, the Contributor who
+		includes the Program in a commercial product offering should do so in a manner
+		which does not create potential liability for other Contributors. Therefore, if
+		a Contributor includes the Program in a commercial product offering, such
+		Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+		every other Contributor ("Indemnified Contributor") against any losses, damages
+		and costs (collectively "Losses") arising from claims, lawsuits and other legal
+		actions brought by a third party against the Indemnified Contributor to the
+		extent caused by the acts or omissions of such Commercial Contributor in
+		connection with its distribution of the Program in a commercial product
+		offering. The obligations in this section do not apply to any claims or Losses
+		relating to any actual or alleged intellectual property infringement. In order
+		to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+		Contributor in writing of such claim, and b) allow the Commercial Contributor to
+		control, and cooperate with the Commercial Contributor in, the defense and any
+		related settlement negotiations. The Indemnified Contributor may participate in
+		any such claim at its own expense.
+		
+		For example, a Contributor might include the Program in a commercial product
+		offering, Product X. That Contributor is then a Commercial Contributor. If that
+		Commercial Contributor then makes performance claims, or offers warranties
+		related to Product X, those performance claims and warranties are such
+		Commercial Contributor's responsibility alone. Under this section, the
+		Commercial Contributor would have to defend claims against the other
+		Contributors related to those performance claims and warranties, and if a court
+		requires any other Contributor to pay any damages as a result, the Commercial
+		Contributor must pay those damages.
+		
+		5. NO WARRANTY
+		
+		EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+		"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+		IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+		NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+		Recipient is solely responsible for determining the appropriateness of using and
+		distributing the Program and assumes all risks associated with its exercise of
+		rights under this Agreement, including but not limited to the risks and costs of
+		program errors, compliance with applicable laws, damage to or loss of data,
+		programs or equipment, and unavailability or interruption of operations.
+		
+		6. DISCLAIMER OF LIABILITY
+		
+		EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+		CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+		SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+		PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+		STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+		OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+		GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+		
+		7. GENERAL
+		
+		If any provision of this Agreement is invalid or unenforceable under applicable
+		law, it shall not affect the validity or enforceability of the remainder of the
+		terms of this Agreement, and without further action by the parties hereto, such
+		provision shall be reformed to the minimum extent necessary to make such
+		provision valid and enforceable.
+		
+		If Recipient institutes patent litigation against a Contributor with respect to
+		a patent applicable to software (including a cross-claim or counterclaim in a
+		lawsuit), then any patent licenses granted by that Contributor to such Recipient
+		under this Agreement shall terminate as of the date such litigation is filed. In
+		addition, if Recipient institutes patent litigation against any entity
+		(including a cross-claim or counterclaim in a lawsuit) alleging that the Program
+		itself (excluding combinations of the Program with other software or hardware)
+		infringes such Recipient's patent(s), then such Recipient's rights granted under
+		Section 2(b) shall terminate as of the date such litigation is filed.
+		
+		All Recipient's rights under this Agreement shall terminate if it fails to
+		comply with any of the material terms or conditions of this Agreement and does
+		not cure such failure in a reasonable period of time after becoming aware of
+		such noncompliance. If all Recipient's rights under this Agreement terminate,
+		Recipient agrees to cease use and distribution of the Program as soon as
+		reasonably practicable. However, Recipient's obligations under this Agreement
+		and any licenses granted by Recipient relating to the Program shall continue and
+		survive.
+		
+		Everyone is permitted to copy and distribute copies of this Agreement, but in
+		order to avoid inconsistency the Agreement is copyrighted and may only be
+		modified in the following manner. The Agreement Steward reserves the right to
+		publish new versions (including revisions) of this Agreement from time to time.
+		No one other than the Agreement Steward has the right to modify this Agreement.
+		IBM is the initial Agreement Steward. IBM may assign the responsibility to serve
+		as the Agreement Steward to a suitable separate entity. Each new version of the
+		Agreement will be given a distinguishing version number. The Program (including
+		Contributions) may always be distributed subject to the version of the Agreement
+		under which it was received. In addition, after a new version of the Agreement
+		is published, Contributor may elect to distribute the Program (including its
+		Contributions) under the new version. Except as expressly stated in Sections
+		2(a) and 2(b) above, Recipient receives no rights or licenses to the
+		intellectual property of any Contributor under this Agreement, whether
+		expressly, by implication, estoppel or otherwise. All rights in the Program not
+		expressly granted under this Agreement are reserved.
+		
+		This Agreement is governed by the laws of the State of New York and the
+		intellectual property laws of the United States of America. No party to this
+		Agreement will bring a legal action under this Agreement more than one year
+		after the cause of action arose. Each party waives its rights to a jury trial in
+		any resulting litigation.
+		 
+		 
+    Bnd, Bundle Tool http://www.aqute.biz/Code/Bnd, The Apache License, Version 2.0
+	ALL OTHERS JARS, BY APACHE SOFTWARE FOUNDATION
+	ALL OF THESE ARE LICENSED UNDER The Apache License, Version 2.0 EXCEPT:
+	
+	Apache Commons Logging, 
+	   The Apache Software License, Version 1.1 (commons-logging-1.1.1.jar)
+	  
+		 The Apache Software License, Version 1.1
+		
+		 Redistribution and use in source and binary forms, with or without
+		 modification, are permitted provided that the following conditions
+		 are met:
+		
+		 1. Redistributions of source code must retain the above copyright
+		    notice, this list of conditions and the following disclaimer.
+		
+		 2. Redistributions in binary form must reproduce the above copyright
+		    notice, this list of conditions and the following disclaimer in
+		    the documentation and/or other materials provided with the
+		    distribution.
+		
+		 3. The end-user documentation included with the redistribution,
+		    if any, must include the following acknowledgment:
+		       "This product includes software developed by the
+		        Apache Software Foundation (http://www.apache.org/)."
+		    Alternately, this acknowledgment may appear in the software itself,
+		    if and wherever such third-party acknowledgments normally appear.
+		
+		 4. The names "Apache" and "Apache Software Foundation" must
+		    not be used to endorse or promote products derived from this
+		    software without prior written permission. For written
+		    permission, please contact apache@apache.org.
+		
+		 5. Products derived from this software may not be called "Apache",
+		    nor may "Apache" appear in their name, without prior written
+		    permission of the Apache Software Foundation.
+		
+		 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+		 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+		 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+		 DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+		 ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+		 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+		 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+		 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+		 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+		 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+		 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+		 SUCH DAMAGE.
+		
+
+	
\ No newline at end of file
diff --git a/apache-mime4j-0.6/NOTICE.txt b/apache-mime4j-0.6/NOTICE.txt
new file mode 100644
index 0000000..4425db0
--- /dev/null
+++ b/apache-mime4j-0.6/NOTICE.txt
@@ -0,0 +1,14 @@
+   =========================================================================

+   ==      NOTICE file for use with the Apache License, Version 2.0,      ==

+   =========================================================================

+   

+   Apache JAMES Mime4j

+   Copyright 2004-2008 The Apache Software Foundation

+   
+   This product includes software developed at

+   The Apache Software Foundation (http://www.apache.org/).

+   

+   This product may include/use software, JUnit (http://www.junit.org/),

+   developed by Kent Beck, Erich Gamma, and David Saff

+   License: Common Public License Version 1.0

+   (http://www.opensource.org/licenses/cpl.php)

diff --git a/apache-mime4j-0.6/RELEASE_NOTES.txt b/apache-mime4j-0.6/RELEASE_NOTES.txt
new file mode 100644
index 0000000..2592c18
--- /dev/null
+++ b/apache-mime4j-0.6/RELEASE_NOTES.txt
@@ -0,0 +1,117 @@
+Release 0.6
+-------------------
+
+Mime4J is a flexible MIME parsing library written in Java. SAX, DOM and pull parsing styles are 
+supported.
+
+The 0.6 release brings another round of API enhancements and performance optimizations. There has 
+been a number of notable improvements in the DOM support. MIME stream parser is expected to be
+50% faster when line counting is disabled. Please also note that as of this release Mime4j 
+requires a Java 1.5 compatible runtime.
+
+Notes
+-----
+
+ * Mime4j API is still considered unstable and is likely to change in future releases
+ * The DOM API has been now been comprehensively refactored and the known limitations 
+   addressed. Please report any remaining issues to 
+   https://issues.apache.org/jira/browse/MIME4J.
+ * Some low level functions are available only in the pull parser (recommended for
+   advanced users)
+ * 0.6 contains a mixture of approaches to the parsing of advanced MIME field types. 
+   Limitations are known with these approaches with some relatively uncommon use cases. 
+   A consistent and comprehensive rewrite is planned for 0.7 which should consolidate 
+   and address these.
+ * The former interfaces TextBody and BinaryBody have been changed into abstract subclasses
+   of class SingleBody. Code that implements these interfaces has to be changed accordingly.
+   [https://issues.apache.org/jira/browse/MIME4J-111]
+ * A dedicated class for writing a message has been introduced. Class MessageWriter has now
+   to be used instead of Body.writeTo(OutputStream, int). A short-cut method
+   Message.writeTo(OutputStream) without a mode parameter is also available.
+   [https://issues.apache.org/jira/browse/MIME4J-110]
+ * Class NamedMailbox has been removed. Class Mailbox now has an additional name property.
+   [https://issues.apache.org/jira/browse/MIME4J-107]
+ * Class MessageUtils has been removed. The methods and constants can now be found in class
+   CharsetUtil in the same package.
+   [https://issues.apache.org/jira/browse/MIME4J-106]
+ * Package org.apache.james.mime4j.decoder has been renamed in org.apache.james.mime4j.codec.
+   [https://issues.apache.org/jira/browse/MIME4J-105]
+ * Class AbstractBody has been superseded by SingleBody. AbstractBody has been removed.
+ * BodyFactory introduced allowing more flexible storage for Message parts. TempFileTextBody
+   and TempFileBinaryBody removed.
+   [https://issues.apache.org/jira/browse/MIME4J-87]
+ * Mime4j now has a more flexible mechanism for storing message bodies. Class TempStorage
+   has been superseded by StorageProvider in package org.apache.james.mime4j.storage.
+   The classes TempStorage, TempPath, TempFile and SimpleTempStorage have been removed.
+   [https://issues.apache.org/jira/browse/MIME4J-83]
+ * Temporary text body storage for Message parts now defaults to US-ASCII (was ISO-8859-1)
+
+Detailed change log can be found here:
+
+http://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310521&styleName=Html&version=12313434
+
+
+Release 0.5
+-------------------
+
+Mime4J is a flexible MIME parsing library written in Java. SAX, DOM and pull parsing
+styles are supported.
+
+
+The 0.5 release addresses a number of important issues discovered since 0.4. In 
+particular, it improves Mime4j ability to deal with malformed data streams including 
+those intentionally crafted to cause excessive CPU and memory utilization that can 
+lead to DoS conditions.
+
+This release also fixes a serious bug that can prevent Mime4j from correctly 
+processing binary content.
+
+Detailed change log can be found here:
+
+https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310521&styleName=Html&version=12313178
+
+Notes
+-----
+ * Mime4j API is still considered unstable and is likely to change in future releases
+ * DOM support has known limitations and some roundtrip issues remain to be resolved
+ * Some low level functions are available only in the pull parser (recommended for 
+   advanced users)
+
+
+
+Release 0.4
+-------------------
+
+Mime4J is a flexible MIME parsing library written in Java. SAX, DOM and pull parsing
+styles are supported.
+
+The 0.4 release brings a number of significant improvements in terms of 
+supported capabilities, flexibility and performance: 
+
+* Revised and improved public API with support for pull parsing
+
+* Support for parsing of 'headless' messages transmitted using non SMTP 
+  transports such as HTTP
+
+* Reduced external dependencies. Mime4j is no longer directly dependent on log4j 
+  and commons-io
+
+* Improved parsing performance (up to 10x for large messages)
+
+* More comprehensive header parsing including support for RFC1864, RFC2045, 
+  RFC2183, RFC2557 and RFC3066
+
+* Revised packaging and exception hierarchy. MimeException now extends
+  IOException.
+
+Detailed change log can be found here:
+
+http://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310521&styleName=Html&version=12312483
+
+Notes
+-----
+ * 0.4 contains numerous API improvements and is not binary compatible with 0.3
+ * Mime4j API is still considered unstable and is likely to change in future releases
+ * DOM support has known limitations and some roundtrip issues remain to be resolved
+ * Some low level functions are available only in the pull parser (recommended for 
+   advanced users)
diff --git a/apache-mime4j-0.6/benchmarks/resources/long-multipart.msg b/apache-mime4j-0.6/benchmarks/resources/long-multipart.msg
new file mode 100644
index 0000000..ca4d93e
--- /dev/null
+++ b/apache-mime4j-0.6/benchmarks/resources/long-multipart.msg
@@ -0,0 +1,684 @@
+Date: Fri, 27 Apr 2007 16:08:23 +0200
+From: Foo Bar <bar@example.com>
+MIME-Version: 1.0
+To:  foo@example.com
+Subject: This is a rather long multipart message.
+Content-Type: multipart/mixed; boundary="------------090404080405080108000909"
+
+This is a multi-part message in MIME format.
+--------------090404080405080108000909
+Content-Type: text/plain; charset=ISO-8859-15
+Content-Transfer-Encoding: 7bit
+
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+1111111111111111111111111111111111111111111111111111111111111111111111111111111
+--------------090404080405080108000909
+Content-Type: text/plain; charset=ISO-8859-15
+Content-Transfer-Encoding: 7bit
+
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+2222222222222222222222222222222222222222222222222222222222222222222222222222222
+--------------090404080405080108000909
+Content-Type: text/plain; charset=ISO-8859-15
+Content-Transfer-Encoding: 7bit
+
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+3333333333333333333333333333333333333333333333333333333333333333333333333333333
+--------------090404080405080108000909
+Content-Type: text/plain; charset=ISO-8859-15
+Content-Transfer-Encoding: 7bit
+
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+4444444444444444444444444444444444444444444444444444444444444444444444444444444
+--------------090404080405080108000909
+Content-Type: text/plain; charset=ISO-8859-15
+Content-Transfer-Encoding: 7bit
+
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+5555555555555555555555555555555555555555555555555555555555555555555555555555555
+--------------090404080405080108000909--
+
diff --git a/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/Base64InputStreamBench.java b/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/Base64InputStreamBench.java
new file mode 100644
index 0000000..7c03f47
--- /dev/null
+++ b/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/Base64InputStreamBench.java
@@ -0,0 +1,109 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Random;
+
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.james.mime4j.codec.Base64InputStream;
+import org.apache.james.mime4j.codec.CodecUtil;
+
+public class Base64InputStreamBench {
+
+    public static void main(String[] args) throws Exception {
+        byte[] data = initData(2 * 1024 * 1024);
+        byte[] encoded = encode(data);
+
+        // decoder test to make sure everything is okay
+
+        testDecode(data, encoded);
+
+        // warmup
+
+        OutputStream nullOut = new NullOutputStream();
+
+        for (int i = 0; i < 5; i++) {
+            ByteArrayInputStream ed = new ByteArrayInputStream(encoded);
+            InputStream in = new Base64InputStream(ed);
+            CodecUtil.copy(in, nullOut);
+        }
+        Thread.sleep(100);
+
+        // test
+
+        long t0 = System.currentTimeMillis();
+
+        final int repetitions = 50;
+        for (int i = 0; i < repetitions; i++) {
+            ByteArrayInputStream ed = new ByteArrayInputStream(encoded);
+            InputStream in = new Base64InputStream(ed);
+            CodecUtil.copy(in, nullOut);
+        }
+
+        long dt = System.currentTimeMillis() - t0;
+        long totalBytes = data.length * (long) repetitions;
+
+        double mbPerSec = (totalBytes / 1024.0 / 1024) / (dt / 1000.0);
+
+        System.out.println(dt + " ms");
+        System.out.println(totalBytes + " bytes");
+        System.out.println(mbPerSec + " mb/sec");
+    }
+
+    private static byte[] initData(int size) {
+        Random random = new Random(size);
+        byte[] data = new byte[size];
+        random.nextBytes(data);
+        return data;
+    }
+
+    private static byte[] encode(byte[] data) throws IOException {
+        InputStream in = new ByteArrayInputStream(data);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeBase64(in, out);
+        return out.toByteArray();
+    }
+
+    private static void testDecode(byte[] data, final byte[] encoded)
+            throws IOException {
+        ByteArrayInputStream ed = new ByteArrayInputStream(encoded);
+        InputStream in = new Base64InputStream(ed);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.copy(in, out);
+
+        compare(data, out.toByteArray());
+    }
+
+    private static void compare(byte[] expected, byte[] actual) {
+        if (expected.length != actual.length)
+            throw new AssertionError("length: " + expected.length + ", "
+                    + actual.length);
+
+        for (int i = 0; i < expected.length; i++)
+            if (expected[i] != actual[i])
+                throw new AssertionError("value @ " + i);
+    }
+
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/Base64OutputStreamBench.java b/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/Base64OutputStreamBench.java
new file mode 100644
index 0000000..335e76a
--- /dev/null
+++ b/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/Base64OutputStreamBench.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+import java.io.OutputStream;
+import java.util.Random;
+
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.james.mime4j.codec.Base64OutputStream;
+
+public class Base64OutputStreamBench {
+
+    public static void main(String[] args) throws Exception {
+        byte[] data = initData(1024);
+
+        OutputStream nullOut = new NullOutputStream();
+        Base64OutputStream base64Out = new Base64OutputStream(nullOut);
+
+        // warmup
+
+        for (int i = 0; i < 2000; i++) {
+            base64Out.write(data);
+        }
+        Thread.sleep(100);
+
+        // test
+
+        long t0 = System.currentTimeMillis();
+
+        final int repetitions = 500000;
+        for (int i = 0; i < repetitions; i++) {
+            base64Out.write(data);
+        }
+        base64Out.close();
+
+        long dt = System.currentTimeMillis() - t0;
+        long totalBytes = data.length * (long) repetitions;
+
+        double mbPerSec = (totalBytes / 1024.0 / 1024) / (dt / 1000.0);
+
+        System.out.println(dt + " ms");
+        System.out.println(totalBytes + " bytes");
+        System.out.println(mbPerSec + " mb/sec");
+    }
+
+    private static byte[] initData(int size) {
+        Random random = new Random(size);
+        byte[] data = new byte[size];
+        random.nextBytes(data);
+        return data;
+    }
+
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/LongMultipartReadBench.java b/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/LongMultipartReadBench.java
new file mode 100644
index 0000000..30dbfed
--- /dev/null
+++ b/apache-mime4j-0.6/benchmarks/src/org/apache/james/mime4j/LongMultipartReadBench.java
@@ -0,0 +1,189 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.message.Header;
+import org.apache.james.mime4j.message.Message;
+import org.apache.james.mime4j.message.SimpleContentHandler;
+import org.apache.james.mime4j.parser.AbstractContentHandler;
+import org.apache.james.mime4j.parser.ContentHandler;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+import org.apache.james.mime4j.storage.DefaultStorageProvider;
+import org.apache.james.mime4j.storage.MemoryStorageProvider;
+
+public class LongMultipartReadBench {
+
+    public static void main(String[] args) throws Exception {
+
+        byte[] content = loadMessage("long-multipart.msg");
+        if (content == null) {
+            System.err.println("Test message not found");
+            return;
+        }
+
+        int testNumber = args.length > 0 ? Integer.parseInt(args[0]) : 0;
+
+        Test test = createTest(testNumber);
+        if (test == null) {
+            System.err.println("No such test: " + testNumber);
+            return;
+        }
+
+        int repetitions = args.length > 1 ? Integer.parseInt(args[1]) : 25000;
+
+        System.out.println("Multipart message read.");
+        System.out.println("No of repetitions: " + repetitions);
+        System.out.println("Content length: " + content.length);
+        System.out.println("Test: " + test.getClass().getSimpleName());
+        
+        System.out.print("Warmup... ");
+        long t0 = System.currentTimeMillis();
+        while (System.currentTimeMillis() - t0 < 1500) {
+            test.run(content, 10);
+        }
+        System.out.println("done");
+
+        System.out.println("--------------------------------");
+
+        long start = System.currentTimeMillis();
+        test.run(content, repetitions);
+        long finish = System.currentTimeMillis();
+
+        double seconds = (finish - start) / 1000.0;
+        double mb = content.length * repetitions / 1024.0 / 1024;
+        System.out.printf("Execution time: %f sec\n", seconds);
+        System.out.printf("%.2f messages/sec\n", repetitions / seconds);
+        System.out.printf("%.2f mb/sec\n", mb / seconds);
+    }
+
+    private static Test createTest(int testNumber) {
+        switch (testNumber) {
+        case 0:
+            return new MimeTokenStreamTest();
+        case 1:
+            return new AbstractContentHandlerTest();
+        case 2:
+            return new SimpleContentHandlerTest();
+        case 3:
+            return new MessageTest();
+        default:
+            return null;
+        }
+    }
+
+    private static byte[] loadMessage(String resourceName) throws IOException {
+        ClassLoader cl = LongMultipartReadBench.class.getClassLoader();
+
+        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
+        InputStream instream = cl.getResourceAsStream(resourceName);
+        if (instream == null) {
+            return null;
+        }
+        try {
+            CodecUtil.copy(instream, outstream);
+        } finally {
+            instream.close();
+        }
+
+        return outstream.toByteArray();
+    }
+
+    private interface Test {
+        void run(byte[] content, int repetitions) throws Exception;
+    }
+
+    private static final class MimeTokenStreamTest implements Test {
+        public void run(byte[] content, int repetitions) throws Exception {
+            MimeTokenStream stream = new MimeTokenStream();
+            for (int i = 0; i < repetitions; i++) {
+                stream.parse(new ByteArrayInputStream(content));
+                for (int state = stream.getState(); state != MimeTokenStream.T_END_OF_STREAM; state = stream
+                        .next()) {
+                }
+            }
+        }
+    }
+
+    private static final class AbstractContentHandlerTest implements Test {
+        public void run(byte[] content, int repetitions) throws Exception {
+            ContentHandler contentHandler = new AbstractContentHandler() {
+            };
+
+            for (int i = 0; i < repetitions; i++) {
+                MimeStreamParser parser = new MimeStreamParser();
+                parser.setContentHandler(contentHandler);
+                parser.parse(new ByteArrayInputStream(content));
+            }
+        }
+    }
+
+    private static final class SimpleContentHandlerTest implements Test {
+        public void run(byte[] content, int repetitions) throws Exception {
+            ContentHandler contentHandler = new SimpleContentHandler() {
+                @Override
+                public void bodyDecoded(BodyDescriptor bd, InputStream is)
+                        throws IOException {
+                }
+
+                @Override
+                public void headers(Header header) {
+                }
+            };
+
+            for (int i = 0; i < repetitions; i++) {
+                MimeStreamParser parser = new MimeStreamParser();
+                parser.setContentHandler(contentHandler);
+                parser.parse(new ByteArrayInputStream(content));
+            }
+        }
+    }
+
+    private static final class MessageTest implements Test {
+        public void run(byte[] content, int repetitions) throws Exception {
+            DefaultStorageProvider.setInstance(new MemoryStorageProvider());
+
+            for (int i = 0; i < repetitions; i++) {
+                new Message(new ByteArrayInputStream(content));
+            }
+        }
+    }
+
+    /*
+    // requires mail.jar and activation.jar to be present
+    private static final class MimeMessageTest implements Test {
+        public void run(byte[] content, int repetitions) throws Exception {
+            for (int i = 0; i < repetitions; i++) {
+                MimeMessage mm = new MimeMessage(null, new ByteArrayInputStream(content));
+                Multipart multipart = (Multipart) mm.getContent();
+                multipart.getCount(); // force parsing
+            }
+        }
+    }
+    */
+
+}
diff --git a/apache-mime4j-0.6/doap_James_Mime4j.rdf b/apache-mime4j-0.6/doap_James_Mime4j.rdf
new file mode 100644
index 0000000..fc2512b
--- /dev/null
+++ b/apache-mime4j-0.6/doap_James_Mime4j.rdf
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl"?>
+<rdf:RDF xml:lang="en"
+         xmlns="http://usefulinc.com/ns/doap#" 
+         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
+         xmlns:asfext="http://projects.apache.org/ns/asfext#"
+         xmlns:foaf="http://xmlns.com/foaf/0.1/">
+<!--
+   $HeadURL$
+   $Revision$
+   $Date$
+
+   ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.
+   ====================================================================
+
+   This software consists of voluntary contributions made by many
+   individuals on behalf of the Apache Software Foundation.  For more
+   information on the Apache Software Foundation, please see
+   <http://www.apache.org />.
+-->
+
+  <Project rdf:about="http://james.apache.org/mime4j/">
+    <license rdf:resource="http://usefulinc.com/doap/licenses/asl20" />
+    <name>Apache James Mime4j</name>
+    <homepage rdf:resource="http://james.apache.org/mime4j/" />
+    <asfext:pmc rdf:resource="http://james.apache.org" />
+    <shortdesc>
+Mime4j can be used to parse e-mail message streams in plain rfc822 and MIME format
+and to build a tree representation of an e-mail message.
+    </shortdesc>
+    <description>
+Mime4j provides a parser for e-mail message streams in plain rfc822 and MIME format. 
+The parser uses a callback mechanism to report parsing events such as the start of 
+an entity header, the start of a body. The parser has been designed to be extremely 
+tolerant against messages violating the standards. Mime4j can also be used to build 
+a tree representation of an e-mail message
+    </description>
+    <bug-database rdf:resource="http://issues.apache.org/jira/browse/MIME4J" />
+    <mailing-list rdf:resource="http://james.apache.org/mime4j/mail-lists.html" />
+    <download-page rdf:resource="http://james.apache.org/download.cgi" />
+    <programming-language>Java</programming-language>
+    <category rdf:resource="http://projects.apache.org/category/mail" />
+    <category rdf:resource="http://projects.apache.org/category/library" />
+
+    <!-- Multiple releases can be listed, each in its own section -->
+    <release>
+      <Version>
+        <name>Apache James Mime4j 0.5</name>
+        <created>2008-10-18</created>
+        <revision>0.5</revision>
+      </Version>
+      <Version>
+        <name>Apache James Mime4j 0.4</name>
+        <created>2008-08-20</created>
+        <revision>0.4</revision>
+      </Version>
+      <Version>
+        <name>Apache James Mime4j 0.3</name>
+        <created>2007-05-31</created>
+        <revision>0.3</revision>
+      </Version>
+      <Version>
+        <name>Apache James Mime4j 0.2</name>
+        <created>2006-01-09</created>
+        <revision>0.2</revision>
+      </Version>
+    </release>
+
+    <repository>
+      <SVNRepository>
+        <location rdf:resource="http://svn.apache.org/repos/asf/james/mime4j/trunk"/>
+        <browse rdf:resource="http://svn.apache.org/viewvc/james/mime4j/trunk"/>
+      </SVNRepository>
+    </repository>
+
+    <asfext:implements>
+      <asfext:Standard>
+        <asfext:title>Standard for ARPA Internet Text Messages</asfext:title>
+        <asfext:body>IETF</asfext:body>
+        <asfext:id>RFC 822</asfext:id>
+        <asfext:url rdf:resource="http://tools.ietf.org/html/rfc822"/>
+      </asfext:Standard>
+    </asfext:implements>
+    <asfext:implements>
+      <asfext:Standard>
+        <asfext:title>Internet Message Format</asfext:title>
+        <asfext:body>IETF</asfext:body>
+        <asfext:id>RFC 2822</asfext:id>
+        <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2822"/>
+      </asfext:Standard>
+    </asfext:implements>
+    <asfext:implements>
+      <asfext:Standard>
+        <asfext:title>Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</asfext:title>
+        <asfext:body>IETF</asfext:body>
+        <asfext:id>RFC 2045</asfext:id>
+        <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2045"/>
+      </asfext:Standard>
+    </asfext:implements>
+    <asfext:implements>
+      <asfext:Standard>
+        <asfext:title>Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types</asfext:title>
+        <asfext:body>IETF</asfext:body>
+        <asfext:id>RFC 2046</asfext:id>
+        <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2046"/>
+      </asfext:Standard>
+    </asfext:implements>
+    <asfext:implements>
+      <asfext:Standard>
+        <asfext:title>Multipurpose Internet Mail Extensions (MIME) Part Three: Message Header Extensions for Non-ASCII Text</asfext:title>
+        <asfext:body>IETF</asfext:body>
+        <asfext:id>RFC 2047</asfext:id>
+        <asfext:url rdf:resource="http://tools.ietf.org/html/rfc2047"/>
+      </asfext:Standard>
+    </asfext:implements>
+
+  </Project>
+</rdf:RDF>
diff --git a/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java
new file mode 100644
index 0000000..16ae1d5
--- /dev/null
+++ b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java
@@ -0,0 +1,187 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.samples.dom;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.Date;
+
+import javax.imageio.ImageIO;
+
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.message.BinaryBody;
+import org.apache.james.mime4j.message.BodyFactory;
+import org.apache.james.mime4j.message.BodyPart;
+import org.apache.james.mime4j.message.Message;
+import org.apache.james.mime4j.message.Multipart;
+import org.apache.james.mime4j.message.TextBody;
+import org.apache.james.mime4j.storage.Storage;
+import org.apache.james.mime4j.storage.StorageOutputStream;
+import org.apache.james.mime4j.storage.StorageProvider;
+
+/**
+ * Creates a multipart/mixed message that consists of a text/plain and an
+ * image/png part. The image is created on the fly; a similar technique can be
+ * used to create PDF or XML attachments, for example.
+ */
+public class MultipartMessage {
+
+    public static void main(String[] args) throws Exception {
+        // 1) start with an empty message
+
+        Message message = new Message();
+
+        // 2) set header fields
+
+        // Date and From are required fields
+        message.setDate(new Date());
+        message.setFrom(Mailbox.parse("John Doe <jdoe@machine.example>"));
+
+        // Message-ID should be present
+        message.createMessageId("machine.example");
+
+        // set some optional fields
+        message.setTo(Mailbox.parse("Mary Smith <mary@example.net>"));
+        message.setSubject("An image for you");
+
+        // 3) set a multipart body
+
+        Multipart multipart = new Multipart("mixed");
+
+        // a multipart may have a preamble
+        multipart.setPreamble("This is a multi-part message in MIME format.");
+
+        // first part is text/plain
+        BodyFactory bodyFactory = new BodyFactory();
+        BodyPart textPart = createTextPart(bodyFactory, "Why so serious?");
+        multipart.addBodyPart(textPart);
+
+        // second part is image/png (image is created on the fly)
+        BufferedImage image = renderSampleImage();
+        BodyPart imagePart = createImagePart(bodyFactory, image);
+        multipart.addBodyPart(imagePart);
+
+        // setMultipart also sets the Content-Type header field
+        message.setMultipart(multipart);
+
+        // 4) print message to standard output
+
+        message.writeTo(System.out);
+
+        // 5) message is no longer needed and should be disposed of
+
+        message.dispose();
+    }
+
+    /**
+     * Creates a text part from the specified string.
+     */
+    private static BodyPart createTextPart(BodyFactory bodyFactory, String text) {
+        // Use UTF-8 to encode the specified text
+        TextBody body = bodyFactory.textBody(text, "UTF-8");
+
+        // Create a text/plain body part
+        BodyPart bodyPart = new BodyPart();
+        bodyPart.setText(body);
+        bodyPart.setContentTransferEncoding("quoted-printable");
+
+        return bodyPart;
+    }
+
+    /**
+     * Creates a binary part from the specified image.
+     */
+    private static BodyPart createImagePart(BodyFactory bodyFactory,
+            BufferedImage image) throws IOException {
+        // Create a binary message body from the image
+        StorageProvider storageProvider = bodyFactory.getStorageProvider();
+        Storage storage = storeImage(storageProvider, image, "png");
+        BinaryBody body = bodyFactory.binaryBody(storage);
+
+        // Create a body part with the correct MIME-type and transfer encoding
+        BodyPart bodyPart = new BodyPart();
+        bodyPart.setBody(body, "image/png");
+        bodyPart.setContentTransferEncoding("base64");
+
+        // Specify a filename in the Content-Disposition header (implicitly sets
+        // the disposition type to "attachment")
+        bodyPart.setFilename("smiley.png");
+
+        return bodyPart;
+    }
+
+    /**
+     * Stores the specified image in a Storage object.
+     */
+    private static Storage storeImage(StorageProvider storageProvider,
+            BufferedImage image, String formatName) throws IOException {
+        // An output stream that is capable of building a Storage object.
+        StorageOutputStream out = storageProvider.createStorageOutputStream();
+
+        // Write the image to our output stream. A StorageOutputStream can be
+        // used to create attachments using any API that supports writing a
+        // document to an output stream, e.g. iText's PdfWriter.
+        ImageIO.write(image, formatName, out);
+
+        // Implicitly closes the output stream and returns the data that has
+        // been written to it.
+        return out.toStorage();
+    }
+
+    /**
+     * Draws an image; unrelated to Mime4j.
+     */
+    private static BufferedImage renderSampleImage() {
+        System.setProperty("java.awt.headless", "true");
+
+        final int size = 100;
+
+        BufferedImage img = new BufferedImage(size, size,
+                BufferedImage.TYPE_BYTE_GRAY);
+
+        Graphics2D gfx = img.createGraphics();
+        gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+        gfx.setStroke(new BasicStroke(size / 40f, BasicStroke.CAP_ROUND,
+                BasicStroke.JOIN_ROUND));
+
+        gfx.setColor(Color.BLACK);
+        gfx.setBackground(Color.WHITE);
+        gfx.clearRect(0, 0, size, size);
+
+        int b = size / 30;
+        gfx.drawOval(b, b, size - 1 - 2 * b, size - 1 - 2 * b);
+
+        int esz = size / 7;
+        int ex = (int) (0.27f * size);
+        gfx.drawOval(ex, ex, esz, esz);
+        gfx.drawOval(size - 1 - esz - ex, ex, esz, esz);
+
+        b = size / 5;
+        gfx.drawArc(b, b, size - 1 - 2 * b, size - 1 - 2 * b, 200, 140);
+
+        return img;
+    }
+
+}
diff --git a/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java
new file mode 100644
index 0000000..d99b938
--- /dev/null
+++ b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.samples.dom;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.message.BodyFactory;
+import org.apache.james.mime4j.message.Message;
+import org.apache.james.mime4j.message.TextBody;
+
+/**
+ * This example generates a message very similar to the one from RFC 5322
+ * Appendix A.1.1.
+ */
+public class TextPlainMessage {
+    public static void main(String[] args) throws IOException {
+        // 1) start with an empty message
+
+        Message message = new Message();
+
+        // 2) set header fields
+
+        // Date and From are required fields
+        message.setDate(new Date());
+        message.setFrom(Mailbox.parse("John Doe <jdoe@machine.example>"));
+
+        // Message-ID should be present
+        message.createMessageId("machine.example");
+
+        // set some optional fields
+        message.setTo(Mailbox.parse("Mary Smith <mary@example.net>"));
+        message.setSubject("Saying Hello");
+
+        // 3) set a text body
+
+        BodyFactory bodyFactory = new BodyFactory();
+        TextBody body = bodyFactory.textBody("This is a message just to "
+                + "say hello.\r\nSo, \"Hello\".");
+
+        // note that setText also sets the Content-Type header field
+        message.setText(body);
+
+        // 4) print message to standard output
+
+        message.writeTo(System.out);
+
+        // 5) message is no longer needed and should be disposed of
+
+        message.dispose();
+    }
+}
diff --git a/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java
new file mode 100644
index 0000000..c5b4a94
--- /dev/null
+++ b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java
@@ -0,0 +1,175 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.samples.transform;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Random;
+
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.message.Body;
+import org.apache.james.mime4j.message.BodyFactory;
+import org.apache.james.mime4j.message.BodyPart;
+import org.apache.james.mime4j.message.Message;
+import org.apache.james.mime4j.message.Multipart;
+import org.apache.james.mime4j.message.TextBody;
+import org.apache.james.mime4j.storage.DefaultStorageProvider;
+import org.apache.james.mime4j.storage.StorageProvider;
+import org.apache.james.mime4j.storage.TempFileStorageProvider;
+
+/**
+ * This code should illustrate how to transform a message into another message
+ * without modifying the original.
+ */
+public class TransformMessage {
+
+    // Host name used in message identifiers.
+    private static final String HOSTNAME = "localhost";
+
+    public static void main(String[] args) throws Exception {
+        // Explicitly set a strategy for storing body parts. Usually not
+        // necessary; for most applications the default setting is appropriate.
+        StorageProvider storageProvider = new TempFileStorageProvider();
+        DefaultStorageProvider.setInstance(storageProvider);
+
+        // Create a template message. It would be possible to load a message
+        // from an input stream but for this example a message object is created
+        // from scratch for demonstration purposes.
+        Message template = createTemplate();
+
+        // Create a new message by transforming the template.
+        Message transformed = transform(template);
+
+        // Print transformed message.
+        System.out.println("\n\nTransformed message:\n--------------------\n");
+        transformed.writeTo(System.out);
+
+        // Messages should be disposed of when they are no longer needed.
+        // Disposing of a message also disposes of all child elements (e.g. body
+        // parts) of the message.
+        transformed.dispose();
+
+        // Print original message to illustrate that it was not affected by the
+        // transformation.
+        System.out.println("\n\nOriginal template:\n------------------\n");
+        template.writeTo(System.out);
+
+        // Original message is no longer needed.
+        template.dispose();
+
+        // At this point all temporary files have been deleted because all
+        // messages and body parts have been disposed of properly.
+    }
+
+    /**
+     * Copies the given message and makes some arbitrary changes to the copy.
+     */
+    private static Message transform(Message original) throws IOException {
+        // Create a copy of the template. The copy can be modified without
+        // affecting the original.
+        Message message = new Message(original);
+
+        // In this example we know we have a multipart message. Use
+        // Message#isMultipart() if uncertain.
+        Multipart multipart = (Multipart) message.getBody();
+
+        // Insert a new text/plain body part after every body part of the
+        // template.
+        final int count = multipart.getCount();
+        for (int i = 0; i < count; i++) {
+            String text = "Text inserted after part " + (i + 1);
+            BodyPart bodyPart = createTextPart(text);
+            multipart.addBodyPart(bodyPart, 2 * i + 1);
+        }
+
+        // For no particular reason remove the second binary body part (now
+        // at index four).
+        BodyPart removed = multipart.removeBodyPart(4);
+
+        // The removed body part no longer has a parent entity it belongs to so
+        // it should be disposed of.
+        removed.dispose();
+
+        // Set some headers on the transformed message
+        message.createMessageId(HOSTNAME);
+        message.setSubject("Transformed message");
+        message.setDate(new Date());
+        message.setFrom(Mailbox.parse("John Doe <jdoe@machine.example>"));
+
+        return message;
+    }
+
+    /**
+     * Creates a multipart/mixed message that consists of three parts (one text,
+     * two binary).
+     */
+    private static Message createTemplate() throws IOException {
+        Multipart multipart = new Multipart("mixed");
+
+        BodyPart part1 = createTextPart("This is the first part of the template..");
+        multipart.addBodyPart(part1);
+
+        BodyPart part2 = createRandomBinaryPart(200);
+        multipart.addBodyPart(part2);
+
+        BodyPart part3 = createRandomBinaryPart(300);
+        multipart.addBodyPart(part3);
+
+        Message message = new Message();
+        message.setMultipart(multipart);
+
+        message.setSubject("Template message");
+
+        return message;
+    }
+
+    /**
+     * Creates a text part from the specified string.
+     */
+    private static BodyPart createTextPart(String text) {
+        TextBody body = new BodyFactory().textBody(text, "UTF-8");
+
+        BodyPart bodyPart = new BodyPart();
+        bodyPart.setText(body);
+        bodyPart.setContentTransferEncoding("quoted-printable");
+
+        return bodyPart;
+    }
+
+    /**
+     * Creates a binary part with random content.
+     */
+    private static BodyPart createRandomBinaryPart(int numberOfBytes)
+            throws IOException {
+        byte[] data = new byte[numberOfBytes];
+        new Random().nextBytes(data);
+
+        Body body = new BodyFactory()
+                .binaryBody(new ByteArrayInputStream(data));
+
+        BodyPart bodyPart = new BodyPart();
+        bodyPart.setBody(body, "application/octet-stream");
+        bodyPart.setContentTransferEncoding("base64");
+
+        return bodyPart;
+    }
+
+}
diff --git a/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/tree/MessageTree.java b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/tree/MessageTree.java
new file mode 100644
index 0000000..88b750e
--- /dev/null
+++ b/apache-mime4j-0.6/examples/src/java/org/apache/james/mime4j/samples/tree/MessageTree.java
@@ -0,0 +1,385 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.samples.tree;
+
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.Date;
+import java.util.Map;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeSelectionModel;
+
+import org.apache.james.mime4j.field.AddressListField;
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.DateTimeField;
+import org.apache.james.mime4j.field.UnstructuredField;
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.field.address.MailboxList;
+import org.apache.james.mime4j.message.BinaryBody;
+import org.apache.james.mime4j.message.Body;
+import org.apache.james.mime4j.message.BodyPart;
+import org.apache.james.mime4j.message.Entity;
+import org.apache.james.mime4j.message.Header;
+import org.apache.james.mime4j.message.Message;
+import org.apache.james.mime4j.message.Multipart;
+import org.apache.james.mime4j.message.TextBody;
+import org.apache.james.mime4j.parser.Field;
+
+/**
+ * Displays a parsed Message in a window. The window will be divided into
+ * two panels. The left panel displays the Message tree. Clicking on a 
+ * node in the tree shows information on that node in the right panel.
+ *
+ * Some of this code have been copied from the Java tutorial's JTree section.
+ */
+public class MessageTree extends JPanel implements TreeSelectionListener {
+    private static final long serialVersionUID = 1L;
+
+    private JPanel contentPane;
+    private JTextArea textView;
+    private JTree tree;
+
+    /**
+     * Wraps an Object and associates it with a text. All message parts 
+     * (headers, bodies, multiparts, body parts) will be wrapped in
+     * ObjectWrapper instances before they are added to the JTree instance.
+     */
+    public static class ObjectWrapper {
+        private String text = "";
+        private Object object = null;
+        
+        public ObjectWrapper(String text, Object object) {
+            this.text = text;
+            this.object = object;
+        }
+        
+        @Override
+        public String toString() {
+            return text;
+        }
+        
+        public Object getObject() {
+            return object;
+        }
+    }
+    
+    /**
+     * Creates a new <code>MessageTree</code> instance displaying the 
+     * specified <code>Message</code>.
+     * 
+     * @param message the message to display.
+     */
+    public MessageTree(Message message) {
+        super(new GridLayout(1,0));
+
+        DefaultMutableTreeNode root = createNode(message);
+
+        tree = new JTree(root);
+        tree.getSelectionModel().setSelectionMode(
+                TreeSelectionModel.SINGLE_TREE_SELECTION);
+
+        tree.addTreeSelectionListener(this);
+
+        JScrollPane treeView = new JScrollPane(tree);
+
+        contentPane = new JPanel(new GridLayout(1,0));
+        JScrollPane contentView = new JScrollPane(contentPane);
+
+        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+        splitPane.setLeftComponent(treeView);
+        splitPane.setRightComponent(contentView);
+
+        Dimension minimumSize = new Dimension(100, 50);
+        contentView.setMinimumSize(minimumSize);
+        treeView.setMinimumSize(minimumSize);
+        splitPane.setDividerLocation(250);
+        splitPane.setPreferredSize(new Dimension(750, 500));
+
+        add(splitPane);
+        
+        textView = new JTextArea();
+        textView.setEditable(false);
+        textView.setLineWrap(true);
+        contentPane.add(textView);
+    }
+    
+    /**
+     * Create a node given a Multipart body.
+     * Add the Preamble, all Body parts and the Epilogue to the node.
+     * 
+     * @param multipart the Multipart.
+     * @return the root node of the tree.
+     */
+    private DefaultMutableTreeNode createNode(Header header) {
+        DefaultMutableTreeNode node = new DefaultMutableTreeNode(
+                new ObjectWrapper("Header", header));
+
+        for (Field field : header.getFields()) {
+            String name = field.getName();
+            
+            node.add(new DefaultMutableTreeNode(new ObjectWrapper(name, field)));
+        }        
+
+        return node;
+    }
+    
+    /**
+     * Create a node given a Multipart body.
+     * Add the Preamble, all Body parts and the Epilogue to the node.
+     * 
+     * @param multipart the Multipart.
+     * @return the root node of the tree.
+     */
+    private DefaultMutableTreeNode createNode(Multipart multipart) {
+        DefaultMutableTreeNode node = new DefaultMutableTreeNode(
+                new ObjectWrapper("Multipart", multipart));
+
+        node.add(new DefaultMutableTreeNode(
+                       new ObjectWrapper("Preamble", multipart.getPreamble())));
+        for (BodyPart part : multipart.getBodyParts()) {
+            node.add(createNode(part));
+        }
+        node.add(new DefaultMutableTreeNode(
+                       new ObjectWrapper("Epilogue", multipart.getEpilogue())));
+
+        return node;
+    }
+    
+    /**
+     * Creates the tree nodes given a MIME entity (either a Message or 
+     * a BodyPart).
+     * 
+     * @param entity the entity.
+     * @return the root node of the tree displaying the specified entity and 
+     *         its children.
+     */
+    private DefaultMutableTreeNode createNode(Entity entity) {
+        
+        /*
+         * Create the root node for the entity. It's either a
+         * Message or a Body part.
+         */
+        String type = "Message";
+        if (entity instanceof BodyPart) {
+            type = "Body part";
+        }
+        DefaultMutableTreeNode node = new DefaultMutableTreeNode(
+                                            new ObjectWrapper(type, entity));
+
+        /*
+         * Add the node encapsulating the entity Header.
+         */
+        node.add(createNode(entity.getHeader()));
+        
+        Body body = entity.getBody();
+        
+        if (body instanceof Multipart) {
+            /*
+             * The body of the entity is a Multipart.
+             */
+            
+            node.add(createNode((Multipart) body));
+        } else if (body instanceof Message) {
+            /*
+             * The body is another Message.
+             */
+            
+            node.add(createNode((Message) body));
+            
+        } else {
+            /*
+             * Discrete Body (either of type TextBody or BinaryBody).
+             */
+            type = "Text body";
+            if (body instanceof BinaryBody) {
+                type = "Binary body";
+            }
+            
+            type += " (" + entity.getMimeType() + ")";
+            node.add(new DefaultMutableTreeNode(new ObjectWrapper(type, body)));
+            
+        }
+        
+        return node;
+    }
+    
+    /**
+     * Called whenever the selection changes in the JTree instance showing
+     * the Message nodes.
+     * 
+     * @param e the event.
+     */
+    public void valueChanged(TreeSelectionEvent e) {
+        DefaultMutableTreeNode node = (DefaultMutableTreeNode)
+                tree.getLastSelectedPathComponent();
+
+        textView.setText("");
+        
+        if (node == null) {
+            return;
+        }
+        
+        Object o = ((ObjectWrapper) node.getUserObject()).getObject();
+
+        if (node.isLeaf()) {
+            
+            if (o instanceof TextBody){
+                /*
+                 * A text body. Display its contents.
+                 */
+                TextBody body = (TextBody) o;
+                StringBuilder sb = new StringBuilder();
+                try {
+                    Reader r = body.getReader();
+                    int c;
+                    while ((c = r.read()) != -1) {
+                        sb.append((char) c);
+                    }
+                } catch (IOException ex) {
+                    ex.printStackTrace();
+                }
+                textView.setText(sb.toString());
+                
+            } else if (o instanceof BinaryBody){
+                /*
+                 * A binary body. Display its MIME type and length in bytes.
+                 */
+                BinaryBody body = (BinaryBody) o;
+                int size = 0;
+                try {
+                    InputStream is = body.getInputStream();
+                    while ((is.read()) != -1) {
+                        size++;
+                    }
+                } catch (IOException ex) {
+                    ex.printStackTrace();
+                }
+                textView.setText("Binary body\n"
+                               + "MIME type: " 
+                                   + body.getParent().getMimeType() + "\n" 
+                               + "Size of decoded data: " + size + " bytes");
+                
+            } else if (o instanceof ContentTypeField) {
+                /*
+                 * Content-Type field.
+                 */
+                ContentTypeField field = (ContentTypeField) o;
+                StringBuilder sb = new StringBuilder();
+                sb.append("MIME type: " + field.getMimeType() + "\n");
+                Map<String, String> params = field.getParameters();
+                for (String name : params.keySet()) {
+                    sb.append(name + " = " + params.get(name) + "\n");
+                }
+                textView.setText(sb.toString());
+                
+            } else if (o instanceof AddressListField) {
+                /*
+                 * An address field (From, To, Cc, etc)
+                 */
+                AddressListField field = (AddressListField) o;
+                MailboxList list = field.getAddressList().flatten();
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < list.size(); i++) {
+                    Mailbox mb = list.get(i);
+                    sb.append(mb.getDisplayString() + "\n");
+                }
+                textView.setText(sb.toString());
+                
+            } else if (o instanceof DateTimeField) {
+                Date date = ((DateTimeField) o).getDate();
+                textView.setText(date.toString());                
+            } else if (o instanceof UnstructuredField){
+                textView.setText(((UnstructuredField) o).getValue());                
+            } else if (o instanceof Field){
+                textView.setText(((Field) o).getBody());                
+            } else {
+                /*
+                 * The Object should be a Header or a String containing a 
+                 * Preamble or Epilogue.
+                 */
+                textView.setText(o.toString());                
+            }
+            
+        }
+    }
+    
+    /**
+     * Creates and displays the gui.
+     * 
+     * @param message the Message to display in the tree.
+     */
+    private static void createAndShowGUI(Message message) {
+        /*
+         * Create and set up the window.
+         */
+        JFrame frame = new JFrame("MessageTree");
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        /*
+         * Create and set up the content pane.
+         */
+        MessageTree newContentPane = new MessageTree(message);
+        newContentPane.setOpaque(true);
+        frame.setContentPane(newContentPane);
+
+        /*
+         * Display the window.
+         */
+        frame.pack();
+        frame.setVisible(true);
+    }
+    
+    public static void main(String[] args) {
+        try {
+            
+            final Message message = new Message(new FileInputStream(args[0]));
+            
+            javax.swing.SwingUtilities.invokeLater(new Runnable() {
+                public void run() {
+                    createAndShowGUI(message);
+                }
+            });
+        
+        } catch (ArrayIndexOutOfBoundsException e) {
+            System.err.println("Wrong number of arguments.");
+            System.err.println("Usage: org.mime4j.samples.tree.MessageTree"
+                             + " path/to/message");
+        } catch (FileNotFoundException e) {
+            System.err.println("The file '" + args[0] + "' could not be found.");
+        } catch (IOException e) {
+            System.err.println("The file '" + args[0] + "' could not be read.");
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/pom.xml b/apache-mime4j-0.6/pom.xml
new file mode 100644
index 0000000..27ccf4a
--- /dev/null
+++ b/apache-mime4j-0.6/pom.xml
@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.    
+  -->
+  <parent>
+    <artifactId>james-project</artifactId>
+    <groupId>org.apache.james</groupId>
+    <version>1.2</version>
+    <!-- Either this really points to the james-project/pom.xml or you
+         will have to tune the local repository, later, in this file -->
+    <relativePath>../james-project/project/pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.james</groupId>
+  <artifactId>apache-mime4j</artifactId>
+  <name>Apache JAMES Mime4j</name>
+  <version>0.6</version>
+  <description>Java stream based MIME message parser</description>
+  <url>http://james.apache.org/mime4j</url>
+  <issueManagement>
+    <url>http://issues.apache.org/jira/browse/MIME4J</url>
+  </issueManagement>
+  <inceptionYear>2004</inceptionYear>
+  <distributionManagement>
+    <site>
+      <id>mime4j-website</id>
+      <url>scp://minotaur.apache.org/www/james.apache.org/mime4j/</url>
+    </site>
+  </distributionManagement>
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/james/mime4j/tags/apache-mime4j-0.6</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/james/mime4j/tags/apache-mime4j-0.6</developerConnection>
+    <url>http://svn.apache.org/viewvc/james/mime4j/tags/apache-mime4j-0.6</url>
+  </scm>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>rat-maven-plugin</artifactId>
+        <version>1.0-alpha-3</version>
+        <executions>
+          <execution>
+            <phase>verify</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>javacc-maven-plugin</artifactId>
+        <version>2.4.1</version>
+        <executions>
+          <execution>
+            <id>generate-jjtree</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>jjtree-javacc</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>generate-javacc</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>javacc</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0.2</version>
+        <configuration>
+          <source>${compileSource}</source>
+          <target>${compileSource}</target>
+          <encoding>iso8859-1</encoding>
+        </configuration>
+      </plugin>      
+      <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <archive>
+          <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+            <manifestEntries>
+              <Specification-Title>Apache Mime4j</Specification-Title>
+              <Specification-Version>${pom.version}</Specification-Version>
+              <Specification-Vendor>The Apache Software Foundation</Specification-Vendor>
+              <Implementation-Title>Apache Mime4j</Implementation-Title>
+              <Implementation-Version>${pom.version}</Implementation-Version>
+              <Implementation-Vendor>The Apache Software Foundation</Implementation-Vendor>
+              <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
+              <url>${pom.url}</url>
+            </manifestEntries>
+          </archive>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.5</version>
+        <executions>
+          <execution>
+            <id>create-javadocs</id> <!-- this is used for inheritance merges -->
+            <phase>package</phase> <!-- append to the packaging phase. -->
+            <goals>
+              <goal>javadoc</goal> <!-- goals == mojos -->
+              <goal>jar</goal> <!-- goals == mojos -->
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <excludePackageNames>org.apache.james.mime4j.field.address.parser:org.apache.james.mime4j.field.contentdisposition.parser:org.apache.james.mime4j.field.contenttype.parser:org.apache.james.mime4j.field.datetime.parser:org.apache.james.mime4j.field.language.parser:org.apache.james.mime4j.field.mimeversion.parser:org.apache.james.mime4j.field.structured.parser</excludePackageNames>
+        </configuration>
+      </plugin>
+      <!-- Add NOTICE and LICENSE to generated JAR -->
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <version>1.0</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <resourceBundles>
+                <resourceBundle>org.apache:apache-jar-resource-bundle:1.4</resourceBundle>
+              </resourceBundles>
+              <properties>
+	              <addLicense>true</addLicense>
+              </properties>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+      	<groupId>org.apache.maven.plugins</groupId>
+      	<artifactId>maven-source-plugin</artifactId>
+      	<version>2.0.4</version>
+      	<executions>
+      		<execution>
+      			<id>attach-sources</id>
+      			<goals>
+      				<goal>jar</goal>
+      			</goals>
+      		</execution>
+      	</executions>
+      </plugin>
+
+      <!--
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      -->
+      <plugin>
+      	<groupId>org.apache.felix</groupId>
+      	<artifactId>maven-bundle-plugin</artifactId>
+      	<version>1.4.3</version>
+      	<executions>
+      		<execution>
+      			<id>bundle-manifest</id>
+      			<phase>process-classes</phase>
+      			<goals>
+      				<goal>manifest</goal>
+      			</goals>
+      		</execution>
+      	</executions>
+      	<extensions>true</extensions>
+      	<configuration>
+      		<instructions>
+      			<Export-Package>org.apache.james.mime4j.*</Export-Package>
+      			<Embed-Dependency>*;scope=runtime</Embed-Dependency>
+      		</instructions>
+      	</configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.2-beta-2</version>
+        <configuration>
+          <descriptorSourceDirectory>${basedir}/src/assemble/</descriptorSourceDirectory>
+          <tarLongFileMode>gnu</tarLongFileMode>
+        </configuration>
+        <executions>
+          <execution>
+            <id>make-assembly</id> <!-- this is used for inheritance merges -->
+            <phase>package</phase> <!-- append to the packaging phase. -->
+            <goals>
+              <goal>attached</goal> <!-- goals == mojos -->
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <repositories>
+    <repository>
+      <id>local-mime4j-stage-repository</id>
+      <name>Local mime4j stage repository</name>
+      <!-- Please note that due to http://jira.codehaus.org/browse/MNG-2896 -->
+      <!-- If you don't have james-project checked out in ../james-project -->
+      <!-- you will have to place your absolute path to the project instead -->
+      <!-- of ${basedir}, or, otherwise, manually install the parent poms -->
+      <!--
+           mvn -fignorepom.xml install:install-file 
+              -Dfile=stage\org.apache.james\poms\james-parent-1.1.pom 
+              -Dpackaging=pom 
+              -DgroupId=org.apache.james 
+              -DartifactId=james-parent 
+              -Dversion=1.1
+           mvn -fignorepom.xml install:install-file 
+              -Dfile=stage\org.apache.james\poms\james-project-1.2.pom 
+              -Dpackaging=pom 
+              -DgroupId=org.apache.james 
+              -DartifactId=james-project 
+              -Dversion=1.2
+       -->
+      <url>file://${basedir}/stage</url>
+      <layout>legacy</layout>
+      <snapshots>
+        <enabled>true</enabled>
+        <checksumPolicy>ignore</checksumPolicy>
+      </snapshots>
+      <releases>
+        <enabled>true</enabled>
+        <checksumPolicy>ignore</checksumPolicy>
+      </releases>
+    </repository>
+  </repositories>
+  <dependencies>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+      <version>1.1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.14</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <type>jar</type>
+      <!--  Removed as a workaround for an unidentified M2 bug -->
+      <scope>test</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>1.2</version>
+      <scope>test</scope>
+      <optional>true</optional>
+    </dependency>
+  </dependencies>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <configuration>
+            <onlyCurrentVersion>true</onlyCurrentVersion>
+            <resolutionIds>Closed</resolutionIds>
+        </configuration>
+        <reportSets>
+            <reportSet>
+                <reports>
+                    <report>jira-report</report>
+                </reports>
+            </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.4.3</version>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+        <version>2.4.3</version>
+      </plugin> 
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.5</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+        <version>2.1</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+        <version>2.4</version>
+        <configuration>
+          <targetJdk>${compileSource}</targetJdk>
+          <rulesets>
+            <ruleset>/rulesets/basic.xml</ruleset>
+            <ruleset>/rulesets/controversial.xml</ruleset>
+          </rulesets>
+          <format>xml</format>
+          <linkXref>true</linkXref>
+          <sourceEncoding>utf-8</sourceEncoding>
+          <minimumTokens>100</minimumTokens>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-site-plugin</artifactId>
+        <version>2.0-beta-7</version>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>rat-maven-plugin</artifactId>
+        <version>1.0-alpha-3</version>
+        <configuration>
+          <excludes>
+            <!-- test resources created by JAMES committers / we can't include ALv2 headers there -->
+            <exclude>src/test/resources/testmsgs/*</exclude>
+            <exclude>benchmarks/resources/*.msg</exclude>
+            <!-- 3rd party descriptors distributed via maven repositories
+                 and included "as is" -->
+            <exclude>stage/commons-io/poms/commons-io-1.2.pom</exclude>
+            <exclude>stage/commons-logging/poms/commons-logging-1.1.pom</exclude>
+            <exclude>stage/org.apache.james/xmls/james-parent-1.1-site.xml</exclude>
+            <exclude>stage/org.apache.james/xmls/james-parent-1.1-site_en.xml</exclude>
+            <exclude>stage/org.apache.james/xmls/james-project-1.2-site.xml</exclude>
+            <exclude>stage/org.apache.james/xmls/james-project-1.2-site_en.xml</exclude>
+            <exclude>release.properties</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>taglist-maven-plugin</artifactId>
+        <version>2.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>javacc-maven-plugin</artifactId>
+        <version>2.4.1</version>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <mailingLists>
+    <mailingList>
+            <name>Apache Mime4j Lists</name>
+            <subscribe>mime4j-dev-subscribe@james.apache.org</subscribe>
+            <unsubscribe>mime4j-dev-unsubscribe@james.apache.org</unsubscribe>
+            <post>mime4j-dev@james.apache.org</post>
+            <archive>http://mail-archives.apache.org/mod_mbox/james-mime4j-dev/</archive>
+    </mailingList>
+  </mailingLists>
+  
+  <properties>
+    <compileSource>1.5</compileSource>
+  </properties>
+</project>
diff --git a/apache-mime4j-0.6/src/assemble/bin.xml b/apache-mime4j-0.6/src/assemble/bin.xml
new file mode 100644
index 0000000..6b0cba8
--- /dev/null
+++ b/apache-mime4j-0.6/src/assemble/bin.xml
@@ -0,0 +1,64 @@
+<assembly>

+  <!--

+  Licensed to the Apache Software Foundation (ASF) under one or more

+  contributor license agreements.  See the NOTICE file distributed with

+  this work for additional information regarding copyright ownership.

+  The ASF licenses this file to You under the Apache License, Version 2.0

+  (the "License"); you may not use this file except in compliance with

+  the License.  You may obtain a copy of the License at

+  

+  http://www.apache.org/licenses/LICENSE-2.0

+  

+  Unless required by applicable law or agreed to in writing, software

+  distributed  under the  License is distributed on an "AS IS" BASIS,

+  WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or

+  implied.

+  

+  See the License for the specific language governing permissions and

+  limitations under the License.

+  -->

+  <id>bin</id>

+  <!-- 

+  Generates a jar file including the binary jar and the runtime dependencies.

+  including NOTICE and LICENSE in the root.

+  -->

+  <formats>

+    <format>zip</format>

+    <format>tar.gz</format>

+  </formats>

+  <fileSets>

+    <fileSet>

+      <directory>target/maven-shared-archive-resources/META-INF/</directory>

+      <outputDirectory>/</outputDirectory>

+      <includes>

+        <include>*</include>

+      </includes>

+    </fileSet>

+    <fileSet>

+      <includes>

+        <include>RELEASE_NOTES.txt</include>

+      </includes>

+    </fileSet>

+    <fileSet>

+      <directory>examples</directory>

+    </fileSet>

+    <fileSet>

+      <directory>target</directory>

+      <outputDirectory></outputDirectory>

+      <includes>

+        <include>${artifactId}-${version}.jar</include>

+      </includes>

+    </fileSet>

+    <fileSet>

+      <directory>target/apidocs</directory>

+      <outputDirectory>javadocs</outputDirectory>

+    </fileSet>

+  </fileSets>

+  <dependencySets>

+    <dependencySet>

+      <outputDirectory>/lib/</outputDirectory>

+      <useProjectArtifact>false</useProjectArtifact>

+      <scope>runtime</scope>

+    </dependencySet>

+  </dependencySets>

+</assembly>

diff --git a/apache-mime4j-0.6/src/assemble/src.xml b/apache-mime4j-0.6/src/assemble/src.xml
new file mode 100644
index 0000000..a3d1d69
--- /dev/null
+++ b/apache-mime4j-0.6/src/assemble/src.xml
@@ -0,0 +1,43 @@
+<assembly>

+  <!--

+  Licensed to the Apache Software Foundation (ASF) under one or more

+  contributor license agreements.  See the NOTICE file distributed with

+  this work for additional information regarding copyright ownership.

+  The ASF licenses this file to You under the Apache License, Version 2.0

+  (the "License"); you may not use this file except in compliance with

+  the License.  You may obtain a copy of the License at

+  

+  http://www.apache.org/licenses/LICENSE-2.0

+  

+  Unless required by applicable law or agreed to in writing, software

+  distributed  under the  License is distributed on an "AS IS" BASIS,

+  WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or

+  implied.

+  

+  See the License for the specific language governing permissions and

+  limitations under the License.

+  -->

+  <id>src</id>

+  <!-- 

+  Generates a file including all the source tree excluding files/folders

+  starting with "." , *.bak and the target

+  -->

+  <formats>

+    <format>zip</format>

+    <format>tar.gz</format>

+  </formats>

+  <fileSets>

+    <fileSet>

+      <directory>.</directory>

+      <outputDirectory></outputDirectory>

+      <excludes>

+        <exclude>**/target/**</exclude>

+        <exclude>.*</exclude>

+        <exclude>.*/**</exclude>

+        <exclude>**.bak</exclude>

+        <exclude>lib/**</exclude>

+      </excludes>

+      <useDefaultExcludes>true</useDefaultExcludes>

+    </fileSet>

+  </fileSets>

+</assembly>
diff --git a/apache-mime4j-0.6/src/main/appended-resources/supplemental-models.xml b/apache-mime4j-0.6/src/main/appended-resources/supplemental-models.xml
new file mode 100644
index 0000000..5ca3f6e
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/appended-resources/supplemental-models.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<supplementalDataModels>

+  <!--

+  Licensed to the Apache Software Foundation (ASF) under one or more

+  contributor license agreements.  See the NOTICE file distributed with

+  this work for additional information regarding copyright ownership.

+  The ASF licenses this file to You under the Apache License, Version 2.0

+  (the "License"); you may not use this file except in compliance with

+  the License.  You may obtain a copy of the License at

+  

+  http://www.apache.org/licenses/LICENSE-2.0

+  

+  Unless required by applicable law or agreed to in writing, software

+  distributed  under the  License is distributed on an "AS IS" BASIS,

+  WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or

+  implied.

+  

+  See the License for the specific language governing permissions and

+  limitations under the License.

+  -->

+  <supplement>

+    <project>

+      <groupId>commons-logging</groupId>

+      <artifactId>commons-logging</artifactId>

+      <name>Apache Commons Logging</name>

+      <url>http://jakarta.apache.org/commons/logging/</url>

+      <organization>

+        <name>The Apache Software Foundation</name>

+        <url>http://www.apache.org/</url>

+      </organization>

+      <licenses>

+        <license>

+          <name>Apache License, Version 2.0</name>

+          <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>

+          <distribution>repo</distribution>

+        </license>

+      </licenses>

+    </project>

+  </supplement>

+  <supplement>

+    <project>

+      <groupId>commons-io</groupId>

+      <artifactId>commons-io</artifactId>

+      <name>Apache Commons IO</name>

+      <url>http://jakarta.apache.org/commons/io/</url>

+      <organization>

+        <name>The Apache Software Foundation</name>

+        <url>http://www.apache.org/</url>

+      </organization>

+      <licenses>

+        <license>

+          <name>Apache License, Version 2.0</name>

+          <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>

+          <distribution>repo</distribution>

+        </license>

+      </licenses>

+    </project>

+  </supplement>

+  <supplement>

+    <project>

+      <groupId>log4j</groupId>

+      <artifactId>log4j</artifactId>

+      <name>Apache Log4j</name>

+      <url>http://logging.apache.org/log4j/</url>

+      <organization>

+        <name>The Apache Software Foundation</name>

+        <url>http://www.apache.org/</url>

+      </organization>

+      <licenses>

+        <license>

+          <name>Apache License, Version 2.0</name>

+          <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>

+          <distribution>repo</distribution>

+        </license>

+      </licenses>

+    </project>

+  </supplement>

+  <supplement>

+    <project>

+      <groupId>junit</groupId>

+      <artifactId>junit</artifactId>

+      <name>JUnit</name>

+      <url>http://www.junit.org/</url>

+      <organization>

+      	<name>Kent Beck, Erich Gamma, and David Saff</name>

+      </organization>

+      <licenses>

+        <license>

+          <name>Common Public License Version 1.0</name>

+          <url>http://www.opensource.org/licenses/cpl.php</url>

+        </license>

+      </licenses>

+    </project>

+  </supplement>

+</supplementalDataModels>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/MimeException.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/MimeException.java
new file mode 100644
index 0000000..b93df6c
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/MimeException.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+/**
+ * MIME processing exception.
+ */
+public class MimeException extends Exception {
+
+    private static final long serialVersionUID = 8352821278714188542L;
+
+    /**
+     * Constructs a new MIME exception with the specified detail message.
+     *
+     * @param message detail message
+     */
+    public MimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a MIME exception with the specified cause.
+     *
+     * @param cause cause of the exception
+     */
+    public MimeException(Throwable cause) {
+        super(cause);
+    }
+    
+    /**
+     * Constructs a MIME exception with the specified detail message and cause.
+     *
+     * @param message detail message
+     * @param cause cause of the exception
+     */
+    public MimeException(String message, Throwable cause) {
+        super(message);
+        initCause(cause);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/MimeIOException.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/MimeIOException.java
new file mode 100644
index 0000000..60b3d57
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/MimeIOException.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+import java.io.IOException;
+
+/**
+ * A wrapper class based on {@link IOException} for MIME protocol exceptions.
+ */
+public class MimeIOException extends IOException {
+
+    private static final long serialVersionUID = 5393613459533735409L;
+
+    /**
+     * Creates a new MimeIOException from the specified detail message.
+     * 
+     * @param message
+     *            detail message.
+     */
+    public MimeIOException(String message) {
+        this(new MimeException(message));
+    }
+
+    /**
+     * Constructs an IO exception based on {@link MimeException}.
+     * 
+     * @param cause
+     *            the cause.
+     */
+    public MimeIOException(MimeException cause) {
+        super(cause.getMessage());
+        initCause(cause);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java
new file mode 100755
index 0000000..1bf40da
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/Base64InputStream.java
@@ -0,0 +1,280 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.IOException;

+import java.io.InputStream;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+

+/**

+ * Performs Base-64 decoding on an underlying stream.

+ */

+public class Base64InputStream extends InputStream {

+    private static Log log = LogFactory.getLog(Base64InputStream.class);

+

+    private static final int ENCODED_BUFFER_SIZE = 1536;

+

+    private static final int[] BASE64_DECODE = new int[256];

+

+    static {

+        for (int i = 0; i < 256; i++)

+            BASE64_DECODE[i] = -1;

+        for (int i = 0; i < Base64OutputStream.BASE64_TABLE.length; i++)

+            BASE64_DECODE[Base64OutputStream.BASE64_TABLE[i] & 0xff] = i;

+    }

+

+    private static final byte BASE64_PAD = '=';

+

+    private static final int EOF = -1;

+

+    private final byte[] singleByte = new byte[1];

+

+    private boolean strict;

+

+    private final InputStream in;

+    private boolean closed = false;

+

+    private final byte[] encoded = new byte[ENCODED_BUFFER_SIZE];

+    private int position = 0; // current index into encoded buffer

+    private int size = 0; // current size of encoded buffer

+

+    private final ByteQueue q = new ByteQueue();

+

+    private boolean eof; // end of file or pad character reached

+

+    public Base64InputStream(InputStream in) {

+        this(in, false);

+    }

+

+    public Base64InputStream(InputStream in, boolean strict) {

+        if (in == null)

+            throw new IllegalArgumentException();

+

+        this.in = in;

+        this.strict = strict;

+    }

+

+    @Override

+    public int read() throws IOException {

+        if (closed)

+            throw new IOException("Base64InputStream has been closed");

+

+        while (true) {

+            int bytes = read0(singleByte, 0, 1);

+            if (bytes == EOF)

+                return EOF;

+

+            if (bytes == 1)

+                return singleByte[0] & 0xff;

+        }

+    }

+

+    @Override

+    public int read(byte[] buffer) throws IOException {

+        if (closed)

+            throw new IOException("Base64InputStream has been closed");

+

+        if (buffer == null)

+            throw new NullPointerException();

+

+        if (buffer.length == 0)

+            return 0;

+

+        return read0(buffer, 0, buffer.length);

+    }

+

+    @Override

+    public int read(byte[] buffer, int offset, int length) throws IOException {

+        if (closed)

+            throw new IOException("Base64InputStream has been closed");

+

+        if (buffer == null)

+            throw new NullPointerException();

+

+        if (offset < 0 || length < 0 || offset + length > buffer.length)

+            throw new IndexOutOfBoundsException();

+

+        if (length == 0)

+            return 0;

+

+        return read0(buffer, offset, offset + length);

+    }

+

+    @Override

+    public void close() throws IOException {

+        if (closed)

+            return;

+

+        closed = true;

+    }

+

+    private int read0(final byte[] buffer, final int from, final int to)

+            throws IOException {

+        int index = from; // index into given buffer

+

+        // check if a previous invocation left decoded bytes in the queue

+

+        int qCount = q.count();

+        while (qCount-- > 0 && index < to) {

+            buffer[index++] = q.dequeue();

+        }

+

+        // eof or pad reached?

+

+        if (eof)

+            return index == from ? EOF : index - from;

+

+        // decode into given buffer

+

+        int data = 0; // holds decoded data; up to four sextets

+        int sextets = 0; // number of sextets

+

+        while (index < to) {

+            // make sure buffer not empty

+

+            while (position == size) {

+                int n = in.read(encoded, 0, encoded.length);

+                if (n == EOF) {

+                    eof = true;

+

+                    if (sextets != 0) {

+                        // error in encoded data

+                        handleUnexpectedEof(sextets);

+                    }

+

+                    return index == from ? EOF : index - from;

+                } else if (n > 0) {

+                    position = 0;

+                    size = n;

+                } else {

+                    assert n == 0;

+                }

+            }

+

+            // decode buffer

+

+            while (position < size && index < to) {

+                int value = encoded[position++] & 0xff;

+

+                if (value == BASE64_PAD) {

+                    index = decodePad(data, sextets, buffer, index, to);

+                    return index - from;

+                }

+

+                int decoded = BASE64_DECODE[value];

+                if (decoded < 0) // -1: not a base64 char

+                    continue;

+

+                data = (data << 6) | decoded;

+                sextets++;

+

+                if (sextets == 4) {

+                    sextets = 0;

+

+                    byte b1 = (byte) (data >>> 16);

+                    byte b2 = (byte) (data >>> 8);

+                    byte b3 = (byte) data;

+

+                    if (index < to - 2) {

+                        buffer[index++] = b1;

+                        buffer[index++] = b2;

+                        buffer[index++] = b3;

+                    } else {

+                        if (index < to - 1) {

+                            buffer[index++] = b1;

+                            buffer[index++] = b2;

+                            q.enqueue(b3);

+                        } else if (index < to) {

+                            buffer[index++] = b1;

+                            q.enqueue(b2);

+                            q.enqueue(b3);

+                        } else {

+                            q.enqueue(b1);

+                            q.enqueue(b2);

+                            q.enqueue(b3);

+                        }

+

+                        assert index == to;

+                        return to - from;

+                    }

+                }

+            }

+        }

+

+        assert sextets == 0;

+        assert index == to;

+        return to - from;

+    }

+

+    private int decodePad(int data, int sextets, final byte[] buffer,

+            int index, final int end) throws IOException {

+        eof = true;

+

+        if (sextets == 2) {

+            // one byte encoded as "XY=="

+

+            byte b = (byte) (data >>> 4);

+            if (index < end) {

+                buffer[index++] = b;

+            } else {

+                q.enqueue(b);

+            }

+        } else if (sextets == 3) {

+            // two bytes encoded as "XYZ="

+

+            byte b1 = (byte) (data >>> 10);

+            byte b2 = (byte) ((data >>> 2) & 0xFF);

+

+            if (index < end - 1) {

+                buffer[index++] = b1;

+                buffer[index++] = b2;

+            } else if (index < end) {

+                buffer[index++] = b1;

+                q.enqueue(b2);

+            } else {

+                q.enqueue(b1);

+                q.enqueue(b2);

+            }

+        } else {

+            // error in encoded data

+            handleUnexpecedPad(sextets);

+        }

+

+        return index;

+    }

+

+    private void handleUnexpectedEof(int sextets) throws IOException {

+        if (strict)

+            throw new IOException("unexpected end of file");

+        else

+            log.warn("unexpected end of file; dropping " + sextets

+                    + " sextet(s)");

+    }

+

+    private void handleUnexpecedPad(int sextets) throws IOException {

+        if (strict)

+            throw new IOException("unexpected padding character");

+        else

+            log.warn("unexpected padding character; dropping " + sextets

+                    + " sextet(s)");

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/Base64OutputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/Base64OutputStream.java
new file mode 100644
index 0000000..538c8d9
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/Base64OutputStream.java
@@ -0,0 +1,321 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.FilterOutputStream;

+import java.io.IOException;

+import java.io.OutputStream;

+import java.util.HashSet;

+import java.util.Set;

+

+/**

+ * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite>

+ * from RFC 2045 <cite>Multipurpose Internet Mail Extensions (MIME) Part One:

+ * Format of Internet Message Bodies</cite> by Freed and Borenstein.

+ * <p>

+ * Code is based on Base64 and Base64OutputStream code from Commons-Codec 1.4.

+ * 

+ * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>

+ */

+public class Base64OutputStream extends FilterOutputStream {

+

+    // Default line length per RFC 2045 section 6.8.

+    private static final int DEFAULT_LINE_LENGTH = 76;

+

+    // CRLF line separator per RFC 2045 section 2.1.

+    private static final byte[] CRLF_SEPARATOR = { '\r', '\n' };

+

+    // This array is a lookup table that translates 6-bit positive integer index

+    // values into their "Base64 Alphabet" equivalents as specified in Table 1

+    // of RFC 2045.

+    static final byte[] BASE64_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F',

+            'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',

+            'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',

+            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',

+            't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',

+            '6', '7', '8', '9', '+', '/' };

+

+    // Byte used to pad output.

+    private static final byte BASE64_PAD = '=';

+

+    // This set contains all base64 characters including the pad character. Used

+    // solely to check if a line separator contains any of these characters.

+    private static final Set<Byte> BASE64_CHARS = new HashSet<Byte>();

+

+    static {

+        for (byte b : BASE64_TABLE) {

+            BASE64_CHARS.add(b);

+        }

+        BASE64_CHARS.add(BASE64_PAD);

+    }

+

+    // Mask used to extract 6 bits

+    private static final int MASK_6BITS = 0x3f;

+

+    private static final int ENCODED_BUFFER_SIZE = 2048;

+

+    private final byte[] singleByte = new byte[1];

+

+    private final int lineLength;

+    private final byte[] lineSeparator;

+

+    private boolean closed = false;

+

+    private final byte[] encoded;

+    private int position = 0;

+

+    private int data = 0;

+    private int modulus = 0;

+

+    private int linePosition = 0;

+

+    /**

+     * Creates a <code>Base64OutputStream</code> that writes the encoded data

+     * to the given output stream using the default line length (76) and line

+     * separator (CRLF).

+     * 

+     * @param out

+     *            underlying output stream.

+     */

+    public Base64OutputStream(OutputStream out) {

+        this(out, DEFAULT_LINE_LENGTH, CRLF_SEPARATOR);

+    }

+

+    /**

+     * Creates a <code>Base64OutputStream</code> that writes the encoded data

+     * to the given output stream using the given line length and the default

+     * line separator (CRLF).

+     * <p>

+     * The given line length will be rounded up to the nearest multiple of 4. If

+     * the line length is zero then the output will not be split into lines.

+     * 

+     * @param out

+     *            underlying output stream.

+     * @param lineLength

+     *            desired line length.

+     */

+    public Base64OutputStream(OutputStream out, int lineLength) {

+        this(out, lineLength, CRLF_SEPARATOR);

+    }

+

+    /**

+     * Creates a <code>Base64OutputStream</code> that writes the encoded data

+     * to the given output stream using the given line length and line

+     * separator.

+     * <p>

+     * The given line length will be rounded up to the nearest multiple of 4. If

+     * the line length is zero then the output will not be split into lines and

+     * the line separator is ignored.

+     * <p>

+     * The line separator must not include characters from the BASE64 alphabet

+     * (including the padding character <code>=</code>).

+     * 

+     * @param out

+     *            underlying output stream.

+     * @param lineLength

+     *            desired line length.

+     * @param lineSeparator

+     *            line separator to use.

+     */

+    public Base64OutputStream(OutputStream out, int lineLength,

+            byte[] lineSeparator) {

+        super(out);

+

+        if (out == null)

+            throw new IllegalArgumentException();

+        if (lineLength < 0)

+            throw new IllegalArgumentException();

+        checkLineSeparator(lineSeparator);

+

+        this.lineLength = lineLength;

+        this.lineSeparator = new byte[lineSeparator.length];

+        System.arraycopy(lineSeparator, 0, this.lineSeparator, 0,

+                lineSeparator.length);

+

+        this.encoded = new byte[ENCODED_BUFFER_SIZE];

+    }

+

+    @Override

+    public final void write(final int b) throws IOException {

+        if (closed)

+            throw new IOException("Base64OutputStream has been closed");

+

+        singleByte[0] = (byte) b;

+        write0(singleByte, 0, 1);

+    }

+

+    @Override

+    public final void write(final byte[] buffer) throws IOException {

+        if (closed)

+            throw new IOException("Base64OutputStream has been closed");

+

+        if (buffer == null)

+            throw new NullPointerException();

+

+        if (buffer.length == 0)

+            return;

+

+        write0(buffer, 0, buffer.length);

+    }

+

+    @Override

+    public final void write(final byte[] buffer, final int offset,

+            final int length) throws IOException {

+        if (closed)

+            throw new IOException("Base64OutputStream has been closed");

+

+        if (buffer == null)

+            throw new NullPointerException();

+

+        if (offset < 0 || length < 0 || offset + length > buffer.length)

+            throw new IndexOutOfBoundsException();

+

+        if (length == 0)

+            return;

+

+        write0(buffer, offset, offset + length);

+    }

+

+    @Override

+    public void flush() throws IOException {

+        if (closed)

+            throw new IOException("Base64OutputStream has been closed");

+

+        flush0();

+    }

+

+    @Override

+    public void close() throws IOException {

+        if (closed)

+            return;

+

+        closed = true;

+        close0();

+    }

+

+    private void write0(final byte[] buffer, final int from, final int to)

+            throws IOException {

+        for (int i = from; i < to; i++) {

+            data = (data << 8) | (buffer[i] & 0xff);

+

+            if (++modulus == 3) {

+                modulus = 0;

+

+                // write line separator if necessary

+

+                if (lineLength > 0 && linePosition >= lineLength) {

+                    // writeLineSeparator() inlined for performance reasons

+

+                    linePosition = 0;

+

+                    if (encoded.length - position < lineSeparator.length)

+                        flush0();

+

+                    for (byte ls : lineSeparator)

+                        encoded[position++] = ls;

+                }

+

+                // encode data into 4 bytes

+

+                if (encoded.length - position < 4)

+                    flush0();

+

+                encoded[position++] = BASE64_TABLE[(data >> 18) & MASK_6BITS];

+                encoded[position++] = BASE64_TABLE[(data >> 12) & MASK_6BITS];

+                encoded[position++] = BASE64_TABLE[(data >> 6) & MASK_6BITS];

+                encoded[position++] = BASE64_TABLE[data & MASK_6BITS];

+

+                linePosition += 4;

+            }

+        }

+    }

+

+    private void flush0() throws IOException {

+        if (position > 0) {

+            out.write(encoded, 0, position);

+            position = 0;

+        }

+    }

+

+    private void close0() throws IOException {

+        if (modulus != 0)

+            writePad();

+

+        // write line separator at the end of the encoded data

+

+        if (lineLength > 0 && linePosition > 0) {

+            writeLineSeparator();

+        }

+

+        flush0();

+    }

+

+    private void writePad() throws IOException {

+        // write line separator if necessary

+

+        if (lineLength > 0 && linePosition >= lineLength) {

+            writeLineSeparator();

+        }

+

+        // encode data into 4 bytes

+

+        if (encoded.length - position < 4)

+            flush0();

+

+        if (modulus == 1) {

+            encoded[position++] = BASE64_TABLE[(data >> 2) & MASK_6BITS];

+            encoded[position++] = BASE64_TABLE[(data << 4) & MASK_6BITS];

+            encoded[position++] = BASE64_PAD;

+            encoded[position++] = BASE64_PAD;

+        } else {

+            assert modulus == 2;

+            encoded[position++] = BASE64_TABLE[(data >> 10) & MASK_6BITS];

+            encoded[position++] = BASE64_TABLE[(data >> 4) & MASK_6BITS];

+            encoded[position++] = BASE64_TABLE[(data << 2) & MASK_6BITS];

+            encoded[position++] = BASE64_PAD;

+        }

+

+        linePosition += 4;

+    }

+

+    private void writeLineSeparator() throws IOException {

+        linePosition = 0;

+

+        if (encoded.length - position < lineSeparator.length)

+            flush0();

+

+        for (byte ls : lineSeparator)

+            encoded[position++] = ls;

+    }

+

+    private void checkLineSeparator(byte[] lineSeparator) {

+        if (lineSeparator.length > ENCODED_BUFFER_SIZE)

+            throw new IllegalArgumentException("line separator length exceeds "

+                    + ENCODED_BUFFER_SIZE);

+

+        for (byte b : lineSeparator) {

+            if (BASE64_CHARS.contains(b)) {

+                throw new IllegalArgumentException(

+                        "line separator must not contain base64 character '"

+                                + (char) (b & 0xff) + "'");

+            }

+        }

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/ByteQueue.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/ByteQueue.java
new file mode 100644
index 0000000..627dfb8
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/ByteQueue.java
@@ -0,0 +1,62 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.util.Iterator;

+

+public class ByteQueue implements Iterable<Byte> {

+

+    private UnboundedFifoByteBuffer buf;

+    private int initialCapacity = -1;

+

+    public ByteQueue() {

+        buf = new UnboundedFifoByteBuffer();

+    }

+

+    public ByteQueue(int initialCapacity) {

+        buf = new UnboundedFifoByteBuffer(initialCapacity);

+        this.initialCapacity = initialCapacity;

+    }

+

+    public void enqueue(byte b) {

+        buf.add(b);

+    }

+

+    public byte dequeue() {

+        return buf.remove();

+    }

+

+    public int count() {

+        return buf.size();

+    }

+

+    public void clear() {

+        if (initialCapacity != -1)

+            buf = new UnboundedFifoByteBuffer(initialCapacity);

+        else

+            buf = new UnboundedFifoByteBuffer();

+    }

+

+    public Iterator<Byte> iterator() {

+        return buf.iterator();

+    }

+

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java
new file mode 100644
index 0000000..55421e6
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/CodecUtil.java
@@ -0,0 +1,107 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.OutputStream;

+

+/**

+ * Utility methods related to codecs.

+ */

+public class CodecUtil {

+    

+    static final int DEFAULT_ENCODING_BUFFER_SIZE = 1024;

+    

+    /**

+     * Copies the contents of one stream to the other.

+     * @param in not null

+     * @param out not null

+     * @throws IOException

+     */

+    public static void copy(final InputStream in, final OutputStream out) throws IOException {

+        final byte[] buffer = new byte[DEFAULT_ENCODING_BUFFER_SIZE];

+        int inputLength;

+        while (-1 != (inputLength = in.read(buffer))) {

+            out.write(buffer, 0, inputLength);

+        }

+    }

+    

+    /**

+     * Encodes the given stream using Quoted-Printable.

+     * This assumes that stream is binary and therefore escapes

+     * all line endings.

+     * @param in not null

+     * @param out not null

+     * @throws IOException

+     */

+    public static void encodeQuotedPrintableBinary(final InputStream in, final OutputStream out) throws IOException {

+        

+        QuotedPrintableEncoder encoder = new QuotedPrintableEncoder(DEFAULT_ENCODING_BUFFER_SIZE, true);

+        encoder.encode(in, out);

+    }

+    

+    /**

+     * Encodes the given stream using Quoted-Printable.

+     * This assumes that stream is text and therefore does not escape

+     * all line endings.

+     * @param in not null

+     * @param out not null

+     * @throws IOException

+     */

+    public static void encodeQuotedPrintable(final InputStream in, final OutputStream out) throws IOException {

+        final QuotedPrintableEncoder encoder = new QuotedPrintableEncoder(DEFAULT_ENCODING_BUFFER_SIZE, false);

+        encoder.encode(in, out);

+    }

+    

+    /**

+     * Encodes the given stream using base64.

+     *

+     * @param in not null

+     * @param out not null

+     * @throws IOException if an I/O error occurs

+     */

+    public static void encodeBase64(final InputStream in, final OutputStream out) throws IOException {

+        Base64OutputStream b64Out = new Base64OutputStream(out);

+        copy(in, b64Out);

+        b64Out.close();

+    }

+    

+    /**

+     * Wraps the given stream in a Quoted-Printable encoder.

+     * @param out not null

+     * @return encoding outputstream 

+     * @throws IOException

+     */

+    public static OutputStream wrapQuotedPrintable(final OutputStream out, boolean binary) throws IOException {

+        return new QuotedPrintableOutputStream(out, binary);

+    }

+    

+    /**

+     * Wraps the given stream in a Base64 encoder.

+     * @param out not null

+     * @return encoding outputstream 

+     * @throws IOException

+     */

+    public static OutputStream wrapBase64(final OutputStream out) throws IOException {

+        return new Base64OutputStream(out);

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
new file mode 100644
index 0000000..ad12634
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/DecoderUtil.java
@@ -0,0 +1,252 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.ByteArrayInputStream;

+import java.io.ByteArrayOutputStream;

+import java.io.IOException;

+import java.io.UnsupportedEncodingException;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.util.CharsetUtil;

+

+/**

+ * Static methods for decoding strings, byte arrays and encoded words.

+ */

+public class DecoderUtil {

+    private static Log log = LogFactory.getLog(DecoderUtil.class);

+    

+    /**

+     * Decodes a string containing quoted-printable encoded data. 

+     * 

+     * @param s the string to decode.

+     * @return the decoded bytes.

+     */

+    public static byte[] decodeBaseQuotedPrintable(String s) {

+        ByteArrayOutputStream baos = new ByteArrayOutputStream();

+        

+        try {

+            byte[] bytes = s.getBytes("US-ASCII");

+            

+            QuotedPrintableInputStream is = new QuotedPrintableInputStream(

+                                               new ByteArrayInputStream(bytes));

+            

+            int b = 0;

+            while ((b = is.read()) != -1) {

+                baos.write(b);

+            }

+        } catch (IOException e) {

+            /*

+             * This should never happen!

+             */

+            log.error(e);

+        }

+        

+        return baos.toByteArray();

+    }

+    

+    /**

+     * Decodes a string containing base64 encoded data. 

+     * 

+     * @param s the string to decode.

+     * @return the decoded bytes.

+     */

+    public static byte[] decodeBase64(String s) {

+        ByteArrayOutputStream baos = new ByteArrayOutputStream();

+        

+        try {

+            byte[] bytes = s.getBytes("US-ASCII");

+            

+            Base64InputStream is = new Base64InputStream(

+                                        new ByteArrayInputStream(bytes));

+            

+            int b = 0;

+            while ((b = is.read()) != -1) {

+                baos.write(b);

+            }

+        } catch (IOException e) {

+            /*

+             * This should never happen!

+             */

+            log.error(e);

+        }

+        

+        return baos.toByteArray();

+    }

+    

+    /**

+     * Decodes an encoded word encoded with the 'B' encoding (described in 

+     * RFC 2047) found in a header field body.

+     * 

+     * @param encodedWord the encoded word to decode.

+     * @param charset the Java charset to use.

+     * @return the decoded string.

+     * @throws UnsupportedEncodingException if the given Java charset isn't 

+     *         supported.

+     */

+    public static String decodeB(String encodedWord, String charset) 

+            throws UnsupportedEncodingException {

+        

+        return new String(decodeBase64(encodedWord), charset);

+    }

+    

+    /**

+     * Decodes an encoded word encoded with the 'Q' encoding (described in 

+     * RFC 2047) found in a header field body.

+     * 

+     * @param encodedWord the encoded word to decode.

+     * @param charset the Java charset to use.

+     * @return the decoded string.

+     * @throws UnsupportedEncodingException if the given Java charset isn't 

+     *         supported.

+     */

+    public static String decodeQ(String encodedWord, String charset)

+            throws UnsupportedEncodingException {

+           

+        /*

+         * Replace _ with =20

+         */

+        StringBuilder sb = new StringBuilder(128);

+        for (int i = 0; i < encodedWord.length(); i++) {

+            char c = encodedWord.charAt(i);

+            if (c == '_') {

+                sb.append("=20");

+            } else {

+                sb.append(c);

+            }

+        }

+        

+        return new String(decodeBaseQuotedPrintable(sb.toString()), charset);

+    }

+    

+    /**

+     * Decodes a string containing encoded words as defined by RFC 2047.

+     * Encoded words in have the form 

+     * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for 

+     * quoted-printable and 'B' or 'b' for Base64.

+     * 

+     * @param body the string to decode.

+     * @return the decoded string.

+     */

+    public static String decodeEncodedWords(String body) {

+        int previousEnd = 0;

+        boolean previousWasEncoded = false;

+

+        StringBuilder sb = new StringBuilder();

+

+        while (true) {

+            int begin = body.indexOf("=?", previousEnd);

+            int end = begin == -1 ? -1 : body.indexOf("?=", begin + 2);

+            if (end == -1) {

+                if (previousEnd == 0)

+                    return body;

+

+                sb.append(body.substring(previousEnd));

+                return sb.toString();

+            }

+            end += 2;

+

+            String sep = body.substring(previousEnd, begin);

+

+            String decoded = decodeEncodedWord(body, begin, end);

+            if (decoded == null) {

+                sb.append(sep);

+                sb.append(body.substring(begin, end));

+            } else {

+                if (!previousWasEncoded || !CharsetUtil.isWhitespace(sep)) {

+                    sb.append(sep);

+                }

+                sb.append(decoded);

+            }

+

+            previousEnd = end;

+            previousWasEncoded = decoded != null;

+        }

+    }

+

+    // return null on error

+    private static String decodeEncodedWord(String body, int begin, int end) {

+        int qm1 = body.indexOf('?', begin + 2);

+        if (qm1 == end - 2)

+            return null;

+

+        int qm2 = body.indexOf('?', qm1 + 1);

+        if (qm2 == end - 2)

+            return null;

+

+        String mimeCharset = body.substring(begin + 2, qm1);

+        String encoding = body.substring(qm1 + 1, qm2);

+        String encodedText = body.substring(qm2 + 1, end - 2);

+

+        String charset = CharsetUtil.toJavaCharset(mimeCharset);

+        if (charset == null) {

+            if (log.isWarnEnabled()) {

+                log.warn("MIME charset '" + mimeCharset + "' in encoded word '"

+                        + body.substring(begin, end) + "' doesn't have a "

+                        + "corresponding Java charset");

+            }

+            return null;

+        } else if (!CharsetUtil.isDecodingSupported(charset)) {

+            if (log.isWarnEnabled()) {

+                log.warn("Current JDK doesn't support decoding of charset '"

+                        + charset + "' (MIME charset '" + mimeCharset

+                        + "' in encoded word '" + body.substring(begin, end)

+                        + "')");

+            }

+            return null;

+        }

+

+        if (encodedText.length() == 0) {

+            if (log.isWarnEnabled()) {

+                log.warn("Missing encoded text in encoded word: '"

+                        + body.substring(begin, end) + "'");

+            }

+            return null;

+        }

+

+        try {

+            if (encoding.equalsIgnoreCase("Q")) {

+                return DecoderUtil.decodeQ(encodedText, charset);

+            } else if (encoding.equalsIgnoreCase("B")) {

+                return DecoderUtil.decodeB(encodedText, charset);

+            } else {

+                if (log.isWarnEnabled()) {

+                    log.warn("Warning: Unknown encoding in encoded word '"

+                            + body.substring(begin, end) + "'");

+                }

+                return null;

+            }

+        } catch (UnsupportedEncodingException e) {

+            // should not happen because of isDecodingSupported check above

+            if (log.isWarnEnabled()) {

+                log.warn("Unsupported encoding in encoded word '"

+                        + body.substring(begin, end) + "'", e);

+            }

+            return null;

+        } catch (RuntimeException e) {

+            if (log.isWarnEnabled()) {

+                log.warn("Could not decode encoded word '"

+                        + body.substring(begin, end) + "'", e);

+            }

+            return null;

+        }

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/EncoderUtil.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/EncoderUtil.java
new file mode 100644
index 0000000..c69c77f
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/EncoderUtil.java
@@ -0,0 +1,609 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.BitSet;
+import java.util.Locale;
+
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Static methods for encoding header field values. This includes encoded-words
+ * as defined in <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a>
+ * or display-names of an e-mail address, for example.
+ */
+public class EncoderUtil {
+    private static final byte[] BASE64_TABLE = Base64OutputStream.BASE64_TABLE;
+    private static final char BASE64_PAD = '=';
+
+    private static final BitSet Q_REGULAR_CHARS = initChars("=_?");
+
+    private static final BitSet Q_RESTRICTED_CHARS = initChars("=_?\"#$%&'(),.:;<>@[\\]^`{|}~");
+
+    private static final int MAX_USED_CHARACTERS = 50;
+
+    private static final String ENC_WORD_PREFIX = "=?";
+    private static final String ENC_WORD_SUFFIX = "?=";
+
+    private static final int ENCODED_WORD_MAX_LENGTH = 75; // RFC 2047
+
+    private static final BitSet TOKEN_CHARS = initChars("()<>@,;:\\\"/[]?=");
+
+    private static final BitSet ATEXT_CHARS = initChars("()<>@.,;:\\\"[]");
+
+    private static BitSet initChars(String specials) {
+        BitSet bs = new BitSet(128);
+        for (char ch = 33; ch < 127; ch++) {
+            if (specials.indexOf(ch) == -1) {
+                bs.set(ch);
+            }
+        }
+        return bs;
+    }
+
+    /**
+     * Selects one of the two encodings specified in RFC 2047.
+     */
+    public enum Encoding {
+        /** The B encoding (identical to base64 defined in RFC 2045). */
+        B,
+        /** The Q encoding (similar to quoted-printable defined in RFC 2045). */
+        Q
+    }
+
+    /**
+     * Indicates the intended usage of an encoded word.
+     */
+    public enum Usage {
+        /**
+         * Encoded word is used to replace a 'text' token in any Subject or
+         * Comments header field.
+         */
+        TEXT_TOKEN,
+        /**
+         * Encoded word is used to replace a 'word' entity within a 'phrase',
+         * for example, one that precedes an address in a From, To, or Cc
+         * header.
+         */
+        WORD_ENTITY
+    }
+
+    private EncoderUtil() {
+    }
+
+    /**
+     * Encodes the display-name portion of an address. See <a
+     * href='http://www.faqs.org/rfcs/rfc5322.html'>RFC 5322</a> section 3.4
+     * and <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a> section
+     * 5.3. The specified string should not be folded.
+     * 
+     * @param displayName
+     *            display-name to encode.
+     * @return encoded display-name.
+     */
+    public static String encodeAddressDisplayName(String displayName) {
+        // display-name = phrase
+        // phrase = 1*( encoded-word / word )
+        // word = atom / quoted-string
+        // atom = [CFWS] 1*atext [CFWS]
+        // CFWS = comment or folding white space
+
+        if (isAtomPhrase(displayName)) {
+            return displayName;
+        } else if (hasToBeEncoded(displayName, 0)) {
+            return encodeEncodedWord(displayName, Usage.WORD_ENTITY);
+        } else {
+            return quote(displayName);
+        }
+    }
+
+    /**
+     * Encodes the local part of an address specification as described in RFC
+     * 5322 section 3.4.1. Leading and trailing CFWS should have been removed
+     * before calling this method. The specified string should not contain any
+     * illegal (control or non-ASCII) characters.
+     * 
+     * @param localPart
+     *            the local part to encode
+     * @return the encoded local part.
+     */
+    public static String encodeAddressLocalPart(String localPart) {
+        // local-part = dot-atom / quoted-string
+        // dot-atom = [CFWS] dot-atom-text [CFWS]
+        // CFWS = comment or folding white space
+
+        if (isDotAtomText(localPart)) {
+            return localPart;
+        } else {
+            return quote(localPart);
+        }
+    }
+
+    /**
+     * Encodes the specified strings into a header parameter as described in RFC
+     * 2045 section 5.1 and RFC 2183 section 2. The specified strings should not
+     * contain any illegal (control or non-ASCII) characters.
+     * 
+     * @param name
+     *            parameter name.
+     * @param value
+     *            parameter value.
+     * @return encoded result.
+     */
+    public static String encodeHeaderParameter(String name, String value) {
+        name = name.toLowerCase(Locale.US);
+
+        // value := token / quoted-string
+        if (isToken(value)) {
+            return name + "=" + value;
+        } else {
+            return name + "=" + quote(value);
+        }
+    }
+
+    /**
+     * Shortcut method that encodes the specified text into an encoded-word if
+     * the text has to be encoded.
+     * 
+     * @param text
+     *            text to encode.
+     * @param usage
+     *            whether the encoded-word is to be used to replace a text token
+     *            or a word entity (see RFC 822).
+     * @param usedCharacters
+     *            number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
+     * @return the specified text if encoding is not necessary or an encoded
+     *         word or a sequence of encoded words otherwise.
+     */
+    public static String encodeIfNecessary(String text, Usage usage,
+            int usedCharacters) {
+        if (hasToBeEncoded(text, usedCharacters))
+            return encodeEncodedWord(text, usage, usedCharacters);
+        else
+            return text;
+    }
+
+    /**
+     * Determines if the specified string has to encoded into an encoded-word.
+     * Returns <code>true</code> if the text contains characters that don't
+     * fall into the printable ASCII character set or if the text contains a
+     * 'word' (sequence of non-whitespace characters) longer than 77 characters
+     * (including characters already used up in the line).
+     * 
+     * @param text
+     *            text to analyze.
+     * @param usedCharacters
+     *            number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
+     * @return <code>true</code> if the specified text has to be encoded into
+     *         an encoded-word, <code>false</code> otherwise.
+     */
+    public static boolean hasToBeEncoded(String text, int usedCharacters) {
+        if (text == null)
+            throw new IllegalArgumentException();
+        if (usedCharacters < 0 || usedCharacters > MAX_USED_CHARACTERS)
+            throw new IllegalArgumentException();
+
+        int nonWhiteSpaceCount = usedCharacters;
+
+        for (int idx = 0; idx < text.length(); idx++) {
+            char ch = text.charAt(idx);
+            if (ch == '\t' || ch == ' ') {
+                nonWhiteSpaceCount = 0;
+            } else {
+                nonWhiteSpaceCount++;
+                if (nonWhiteSpaceCount > 77) {
+                    // Line cannot be folded into multiple lines with no more
+                    // than 78 characters each. Encoding as encoded-words makes
+                    // that possible. One character has to be reserved for
+                    // folding white space; that leaves 77 characters.
+                    return true;
+                }
+
+                if (ch < 32 || ch >= 127) {
+                    // non-printable ascii character has to be encoded
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Encodes the specified text into an encoded word or a sequence of encoded
+     * words separated by space. The text is separated into a sequence of
+     * encoded words if it does not fit in a single one.
+     * <p>
+     * The charset to encode the specified text into a byte array and the
+     * encoding to use for the encoded-word are detected automatically.
+     * <p>
+     * This method assumes that zero characters have already been used up in the
+     * current line.
+     * 
+     * @param text
+     *            text to encode.
+     * @param usage
+     *            whether the encoded-word is to be used to replace a text token
+     *            or a word entity (see RFC 822).
+     * @return the encoded word (or sequence of encoded words if the given text
+     *         does not fit in a single encoded word).
+     * @see #hasToBeEncoded(String, int)
+     */
+    public static String encodeEncodedWord(String text, Usage usage) {
+        return encodeEncodedWord(text, usage, 0, null, null);
+    }
+
+    /**
+     * Encodes the specified text into an encoded word or a sequence of encoded
+     * words separated by space. The text is separated into a sequence of
+     * encoded words if it does not fit in a single one.
+     * <p>
+     * The charset to encode the specified text into a byte array and the
+     * encoding to use for the encoded-word are detected automatically.
+     * 
+     * @param text
+     *            text to encode.
+     * @param usage
+     *            whether the encoded-word is to be used to replace a text token
+     *            or a word entity (see RFC 822).
+     * @param usedCharacters
+     *            number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
+     * @return the encoded word (or sequence of encoded words if the given text
+     *         does not fit in a single encoded word).
+     * @see #hasToBeEncoded(String, int)
+     */
+    public static String encodeEncodedWord(String text, Usage usage,
+            int usedCharacters) {
+        return encodeEncodedWord(text, usage, usedCharacters, null, null);
+    }
+
+    /**
+     * Encodes the specified text into an encoded word or a sequence of encoded
+     * words separated by space. The text is separated into a sequence of
+     * encoded words if it does not fit in a single one.
+     * 
+     * @param text
+     *            text to encode.
+     * @param usage
+     *            whether the encoded-word is to be used to replace a text token
+     *            or a word entity (see RFC 822).
+     * @param usedCharacters
+     *            number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
+     * @param charset
+     *            the Java charset that should be used to encode the specified
+     *            string into a byte array. A suitable charset is detected
+     *            automatically if this parameter is <code>null</code>.
+     * @param encoding
+     *            the encoding to use for the encoded-word (either B or Q). A
+     *            suitable encoding is automatically chosen if this parameter is
+     *            <code>null</code>.
+     * @return the encoded word (or sequence of encoded words if the given text
+     *         does not fit in a single encoded word).
+     * @see #hasToBeEncoded(String, int)
+     */
+    public static String encodeEncodedWord(String text, Usage usage,
+            int usedCharacters, Charset charset, Encoding encoding) {
+        if (text == null)
+            throw new IllegalArgumentException();
+        if (usedCharacters < 0 || usedCharacters > MAX_USED_CHARACTERS)
+            throw new IllegalArgumentException();
+
+        if (charset == null)
+            charset = determineCharset(text);
+
+        String mimeCharset = CharsetUtil.toMimeCharset(charset.name());
+        if (mimeCharset == null) {
+            // cannot happen if charset was originally null
+            throw new IllegalArgumentException("Unsupported charset");
+        }
+
+        byte[] bytes = encode(text, charset);
+
+        if (encoding == null)
+            encoding = determineEncoding(bytes, usage);
+
+        if (encoding == Encoding.B) {
+            String prefix = ENC_WORD_PREFIX + mimeCharset + "?B?";
+            return encodeB(prefix, text, usedCharacters, charset, bytes);
+        } else {
+            String prefix = ENC_WORD_PREFIX + mimeCharset + "?Q?";
+            return encodeQ(prefix, text, usage, usedCharacters, charset, bytes);
+        }
+    }
+
+    /**
+     * Encodes the specified byte array using the B encoding defined in RFC
+     * 2047.
+     * 
+     * @param bytes
+     *            byte array to encode.
+     * @return encoded string.
+     */
+    public static String encodeB(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+
+        int idx = 0;
+        final int end = bytes.length;
+        for (; idx < end - 2; idx += 3) {
+            int data = (bytes[idx] & 0xff) << 16 | (bytes[idx + 1] & 0xff) << 8
+                    | bytes[idx + 2] & 0xff;
+            sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
+            sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
+            sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]);
+            sb.append((char) BASE64_TABLE[data & 0x3f]);
+        }
+
+        if (idx == end - 2) {
+            int data = (bytes[idx] & 0xff) << 16 | (bytes[idx + 1] & 0xff) << 8;
+            sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
+            sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
+            sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]);
+            sb.append(BASE64_PAD);
+
+        } else if (idx == end - 1) {
+            int data = (bytes[idx] & 0xff) << 16;
+            sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
+            sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
+            sb.append(BASE64_PAD);
+            sb.append(BASE64_PAD);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Encodes the specified byte array using the Q encoding defined in RFC
+     * 2047.
+     * 
+     * @param bytes
+     *            byte array to encode.
+     * @param usage
+     *            whether the encoded-word is to be used to replace a text token
+     *            or a word entity (see RFC 822).
+     * @return encoded string.
+     */
+    public static String encodeQ(byte[] bytes, Usage usage) {
+        BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS
+                : Q_RESTRICTED_CHARS;
+
+        StringBuilder sb = new StringBuilder();
+
+        final int end = bytes.length;
+        for (int idx = 0; idx < end; idx++) {
+            int v = bytes[idx] & 0xff;
+            if (v == 32) {
+                sb.append('_');
+            } else if (!qChars.get(v)) {
+                sb.append('=');
+                sb.append(hexDigit(v >>> 4));
+                sb.append(hexDigit(v & 0xf));
+            } else {
+                sb.append((char) v);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Tests whether the specified string is a token as defined in RFC 2045
+     * section 5.1.
+     * 
+     * @param str
+     *            string to test.
+     * @return <code>true</code> if the specified string is a RFC 2045 token,
+     *         <code>false</code> otherwise.
+     */
+    public static boolean isToken(String str) {
+        // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials>
+        // tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" /
+        // <"> / "/" / "[" / "]" / "?" / "="
+        // CTL := 0.- 31., 127.
+
+        final int length = str.length();
+        if (length == 0)
+            return false;
+
+        for (int idx = 0; idx < length; idx++) {
+            char ch = str.charAt(idx);
+            if (!TOKEN_CHARS.get(ch))
+                return false;
+        }
+
+        return true;
+    }
+
+    private static boolean isAtomPhrase(String str) {
+        // atom = [CFWS] 1*atext [CFWS]
+
+        boolean containsAText = false;
+
+        final int length = str.length();
+        for (int idx = 0; idx < length; idx++) {
+            char ch = str.charAt(idx);
+            if (ATEXT_CHARS.get(ch)) {
+                containsAText = true;
+            } else if (!CharsetUtil.isWhitespace(ch)) {
+                return false;
+            }
+        }
+
+        return containsAText;
+    }
+
+    // RFC 5322 section 3.2.3
+    private static boolean isDotAtomText(String str) {
+        // dot-atom-text = 1*atext *("." 1*atext)
+        // atext = ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" /
+        // "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
+
+        char prev = '.';
+
+        final int length = str.length();
+        if (length == 0)
+            return false;
+
+        for (int idx = 0; idx < length; idx++) {
+            char ch = str.charAt(idx);
+
+            if (ch == '.') {
+                if (prev == '.' || idx == length - 1)
+                    return false;
+            } else {
+                if (!ATEXT_CHARS.get(ch))
+                    return false;
+            }
+
+            prev = ch;
+        }
+
+        return true;
+    }
+
+    // RFC 5322 section 3.2.4
+    private static String quote(String str) {
+        // quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS]
+        // qcontent = qtext / quoted-pair
+        // qtext = %d33 / %d35-91 / %d93-126
+        // quoted-pair = ("\" (VCHAR / WSP))
+        // VCHAR = %x21-7E
+        // DQUOTE = %x22
+
+        String escaped = str.replaceAll("[\\\\\"]", "\\\\$0");
+        return "\"" + escaped + "\"";
+    }
+
+    private static String encodeB(String prefix, String text,
+            int usedCharacters, Charset charset, byte[] bytes) {
+        int encodedLength = bEncodedLength(bytes);
+
+        int totalLength = prefix.length() + encodedLength
+                + ENC_WORD_SUFFIX.length();
+        if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) {
+            return prefix + encodeB(bytes) + ENC_WORD_SUFFIX;
+        } else {
+            String part1 = text.substring(0, text.length() / 2);
+            byte[] bytes1 = encode(part1, charset);
+            String word1 = encodeB(prefix, part1, usedCharacters, charset,
+                    bytes1);
+
+            String part2 = text.substring(text.length() / 2);
+            byte[] bytes2 = encode(part2, charset);
+            String word2 = encodeB(prefix, part2, 0, charset, bytes2);
+
+            return word1 + " " + word2;
+        }
+    }
+
+    private static int bEncodedLength(byte[] bytes) {
+        return (bytes.length + 2) / 3 * 4;
+    }
+
+    private static String encodeQ(String prefix, String text, Usage usage,
+            int usedCharacters, Charset charset, byte[] bytes) {
+        int encodedLength = qEncodedLength(bytes, usage);
+
+        int totalLength = prefix.length() + encodedLength
+                + ENC_WORD_SUFFIX.length();
+        if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) {
+            return prefix + encodeQ(bytes, usage) + ENC_WORD_SUFFIX;
+        } else {
+            String part1 = text.substring(0, text.length() / 2);
+            byte[] bytes1 = encode(part1, charset);
+            String word1 = encodeQ(prefix, part1, usage, usedCharacters,
+                    charset, bytes1);
+
+            String part2 = text.substring(text.length() / 2);
+            byte[] bytes2 = encode(part2, charset);
+            String word2 = encodeQ(prefix, part2, usage, 0, charset, bytes2);
+
+            return word1 + " " + word2;
+        }
+    }
+
+    private static int qEncodedLength(byte[] bytes, Usage usage) {
+        BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS
+                : Q_RESTRICTED_CHARS;
+
+        int count = 0;
+
+        for (int idx = 0; idx < bytes.length; idx++) {
+            int v = bytes[idx] & 0xff;
+            if (v == 32) {
+                count++;
+            } else if (!qChars.get(v)) {
+                count += 3;
+            } else {
+                count++;
+            }
+        }
+
+        return count;
+    }
+
+    private static byte[] encode(String text, Charset charset) {
+        ByteBuffer buffer = charset.encode(text);
+        byte[] bytes = new byte[buffer.limit()];
+        buffer.get(bytes);
+        return bytes;
+    }
+
+    private static Charset determineCharset(String text) {
+        // it is an important property of iso-8859-1 that it directly maps
+        // unicode code points 0000 to 00ff to byte values 00 to ff.
+        boolean ascii = true;
+        final int len = text.length();
+        for (int index = 0; index < len; index++) {
+            char ch = text.charAt(index);
+            if (ch > 0xff) {
+                return CharsetUtil.UTF_8;
+            }
+            if (ch > 0x7f) {
+                ascii = false;
+            }
+        }
+        return ascii ? CharsetUtil.US_ASCII : CharsetUtil.ISO_8859_1;
+    }
+
+    private static Encoding determineEncoding(byte[] bytes, Usage usage) {
+        if (bytes.length == 0)
+            return Encoding.Q;
+
+        BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS
+                : Q_RESTRICTED_CHARS;
+
+        int qEncoded = 0;
+        for (int i = 0; i < bytes.length; i++) {
+            int v = bytes[i] & 0xff;
+            if (v != 32 && !qChars.get(v)) {
+                qEncoded++;
+            }
+        }
+
+        int percentage = qEncoded * 100 / bytes.length;
+        return percentage > 30 ? Encoding.B : Encoding.Q;
+    }
+
+    private static char hexDigit(int i) {
+        return i < 10 ? (char) (i + '0') : (char) (i - 10 + 'A');
+    }
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
new file mode 100644
index 0000000..f7e8ab3
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
@@ -0,0 +1,206 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+final class QuotedPrintableEncoder {
+    private static final byte TAB = 0x09;
+    private static final byte SPACE = 0x20;
+    private static final byte EQUALS = 0x3D;
+    private static final byte CR = 0x0D;
+    private static final byte LF = 0x0A;
+    private static final byte QUOTED_PRINTABLE_LAST_PLAIN = 0x7E;
+    private static final int QUOTED_PRINTABLE_MAX_LINE_LENGTH = 76;
+    private static final int QUOTED_PRINTABLE_OCTETS_PER_ESCAPE = 3;
+    private static final byte[] HEX_DIGITS = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+    private final byte[] inBuffer;
+    private final byte[] outBuffer;
+    private final boolean binary;
+    
+    private boolean pendingSpace;
+    private boolean pendingTab;
+    private boolean pendingCR;
+    private int nextSoftBreak;
+    private int outputIndex;
+    private OutputStream out;
+    
+    
+    public QuotedPrintableEncoder(int bufferSize, boolean binary) {
+        inBuffer = new byte[bufferSize];
+        outBuffer = new byte[3*bufferSize];
+        outputIndex = 0;
+        nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
+        out = null;
+        this.binary = binary;
+        pendingSpace = false;
+        pendingTab = false;
+        pendingCR = false;
+    }
+    
+    void initEncoding(final OutputStream out) {
+        this.out = out;
+        pendingSpace = false;
+        pendingTab = false;
+        pendingCR = false;
+        nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
+    }
+    
+    void encodeChunk(byte[] buffer, int off, int len) throws IOException {
+        for (int inputIndex = off; inputIndex < len + off; inputIndex++) {
+            encode(buffer[inputIndex]);
+        }
+    }
+    
+    void completeEncoding() throws IOException {
+        writePending();
+        flushOutput();
+    }
+    
+    public void encode(final InputStream in, final OutputStream out) throws IOException {
+        initEncoding(out);
+        int inputLength;
+        while((inputLength = in.read(inBuffer)) > -1) {
+            encodeChunk(inBuffer, 0, inputLength);
+        }
+        completeEncoding();
+    }
+    
+    private void writePending() throws IOException {
+        if (pendingSpace) {
+            plain(SPACE);
+        } else if (pendingTab) {
+            plain(TAB);
+        } else if (pendingCR) {
+            plain(CR);
+        }
+        clearPending();
+    }
+    
+    private void clearPending() throws IOException {
+        pendingSpace  = false;
+        pendingTab = false;
+        pendingCR = false;
+    }
+    
+    private void encode(byte next) throws IOException {
+        if (next == LF) {
+            if (binary) {
+                writePending();
+                escape(next);
+            } else {
+                if (pendingCR) {
+                    // Expect either space or tab pending 
+                    // but not both
+                    if (pendingSpace) {
+                        escape(SPACE);
+                    } else if (pendingTab) {
+                        escape(TAB);
+                    }
+                    lineBreak();
+                    clearPending();
+                } else {
+                    writePending();
+                    plain(next);
+                }
+            }
+        } else if (next == CR) {
+            if (binary)  {
+                escape(next);
+            } else {
+                pendingCR = true;
+            }
+        } else {
+            writePending();
+            if (next == SPACE) {
+                if (binary)  {
+                    escape(next);
+                } else {
+                    pendingSpace = true;
+                }
+            } else if (next == TAB) {
+                if (binary)  {
+                    escape(next);
+                } else {
+                    pendingTab = true;
+                }
+            } else if (next < SPACE) {
+                escape(next);
+            } else if (next > QUOTED_PRINTABLE_LAST_PLAIN) {
+                escape(next);
+            } else if (next == EQUALS) {
+                escape(next);
+            } else {
+                plain(next);
+            }
+        }
+    }
+    
+    private void plain(byte next) throws IOException {
+        if (--nextSoftBreak <= 1) {
+            softBreak();
+        }
+        write(next);
+    }
+    
+    private void escape(byte next) throws IOException {
+        if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE) {
+            softBreak();
+        }
+        
+        int nextUnsigned = next & 0xff;
+        
+        write(EQUALS);
+        --nextSoftBreak;
+        write(HEX_DIGITS[nextUnsigned >> 4]);
+        --nextSoftBreak;
+        write(HEX_DIGITS[nextUnsigned % 0x10]);
+    }
+    
+    private void write(byte next) throws IOException {
+        outBuffer[outputIndex++] = next;
+        if (outputIndex >= outBuffer.length) {
+            flushOutput();
+        }
+    }
+    
+    private void softBreak() throws IOException {
+        write(EQUALS);
+        lineBreak();
+    }
+
+    private void lineBreak() throws IOException {
+        write(CR);
+        write(LF);
+        nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
+    }
+    
+    void flushOutput() throws IOException {
+        if (outputIndex < outBuffer.length) {
+            out.write(outBuffer, 0, outputIndex);
+        } else {
+            out.write(outBuffer);
+        }
+        outputIndex = 0;
+    }
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
new file mode 100644
index 0000000..b3ea06c
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
@@ -0,0 +1,230 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.IOException;

+import java.io.InputStream;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+

+/**

+ * Performs Quoted-Printable decoding on an underlying stream.

+ */

+public class QuotedPrintableInputStream extends InputStream {

+    private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class);

+    

+    private InputStream stream;

+    ByteQueue byteq = new ByteQueue();

+    ByteQueue pushbackq = new ByteQueue();

+    private byte state = 0;

+    private boolean closed = false;

+

+    public QuotedPrintableInputStream(InputStream stream) {

+        this.stream = stream;

+    }

+    

+    /**

+     * Terminates Quoted-Printable coded content. This method does NOT close 

+     * the underlying input stream.

+     * 

+     * @throws IOException on I/O errors.

+     */

+    @Override

+    public void close() throws IOException {

+        this.closed = true;

+    }

+

+    @Override

+    public int read() throws IOException {

+        if (closed) {

+            throw new IOException("QuotedPrintableInputStream has been closed");

+        }

+        fillBuffer();

+        if (byteq.count() == 0)

+            return -1;

+        else {

+            byte val = byteq.dequeue();

+            if (val >= 0)

+                return val;

+            else

+                return val & 0xFF;

+        }

+    }

+

+    /**

+     * Pulls bytes out of the underlying stream and places them in the

+     * pushback queue.  This is necessary (vs. reading from the

+     * underlying stream directly) to detect and filter out "transport

+     * padding" whitespace, i.e., all whitespace that appears immediately

+     * before a CRLF.

+     *

+     * @throws IOException Underlying stream threw IOException.

+     */

+    private void populatePushbackQueue() throws IOException {

+        //Debug.verify(pushbackq.count() == 0, "PopulatePushbackQueue called when pushback queue was not empty!");

+

+        if (pushbackq.count() != 0)

+            return;

+

+        while (true) {

+            int i = stream.read();

+            switch (i) {

+                case -1:

+                    // stream is done

+                    pushbackq.clear();  // discard any whitespace preceding EOF

+                    return;

+                case ' ':

+                case '\t':

+                    pushbackq.enqueue((byte)i);

+                    break;

+                case '\r':

+                case '\n':

+                    pushbackq.clear();  // discard any whitespace preceding EOL

+                    pushbackq.enqueue((byte)i);

+                    return;

+                default:

+                    pushbackq.enqueue((byte)i);

+                    return;

+            }

+        }

+    }

+

+    /**

+     * Causes the pushback queue to get populated if it is empty, then

+     * consumes and decodes bytes out of it until one or more bytes are

+     * in the byte queue.  This decoding step performs the actual QP

+     * decoding.

+     *

+     * @throws IOException Underlying stream threw IOException.

+     */

+    private void fillBuffer() throws IOException {

+        byte msdChar = 0;  // first digit of escaped num

+        while (byteq.count() == 0) {

+            if (pushbackq.count() == 0) {

+                populatePushbackQueue();

+                if (pushbackq.count() == 0)

+                    return;

+            }

+

+            byte b = pushbackq.dequeue();

+

+            switch (state) {

+                case 0:  // start state, no bytes pending

+                    if (b != '=') {

+                        byteq.enqueue(b);

+                        break;  // state remains 0

+                    } else {

+                        state = 1;

+                        break;

+                    }

+                case 1:  // encountered "=" so far

+                    if (b == '\r') {

+                        state = 2;

+                        break;

+                    } else if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {

+                        state = 3;

+                        msdChar = b;  // save until next digit encountered

+                        break;

+                    } else if (b == '=') {

+                        /*

+                         * Special case when == is encountered.

+                         * Emit one = and stay in this state.

+                         */

+                        if (log.isWarnEnabled()) {

+                            log.warn("Malformed MIME; got ==");

+                        }

+                        byteq.enqueue((byte)'=');

+                        break;

+                    } else {

+                        if (log.isWarnEnabled()) {

+                            log.warn("Malformed MIME; expected \\r or "

+                                    + "[0-9A-Z], got " + b);

+                        }

+                        state = 0;

+                        byteq.enqueue((byte)'=');

+                        byteq.enqueue(b);

+                        break;

+                    }

+                case 2:  // encountered "=\r" so far

+                    if (b == '\n') {

+                        state = 0;

+                        break;

+                    } else {

+                        if (log.isWarnEnabled()) {

+                            log.warn("Malformed MIME; expected " 

+                                    + (int)'\n' + ", got " + b);

+                        }

+                        state = 0;

+                        byteq.enqueue((byte)'=');

+                        byteq.enqueue((byte)'\r');

+                        byteq.enqueue(b);

+                        break;

+                    }

+                case 3:  // encountered =<digit> so far; expecting another <digit> to complete the octet

+                    if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {

+                        byte msd = asciiCharToNumericValue(msdChar);

+                        byte low = asciiCharToNumericValue(b);

+                        state = 0;

+                        byteq.enqueue((byte)((msd << 4) | low));

+                        break;

+                    } else {

+                        if (log.isWarnEnabled()) {

+                            log.warn("Malformed MIME; expected "

+                                     + "[0-9A-Z], got " + b);

+                        }

+                        state = 0;

+                        byteq.enqueue((byte)'=');

+                        byteq.enqueue(msdChar);

+                        byteq.enqueue(b);

+                        break;

+                    }

+                default:  // should never happen

+                    log.error("Illegal state: " + state);

+                    state = 0;

+                    byteq.enqueue(b);

+                    break;

+            }

+        }

+    }

+

+    /**

+     * Converts '0' => 0, 'A' => 10, etc.

+     * @param c ASCII character value.

+     * @return Numeric value of hexadecimal character.

+     */

+    private byte asciiCharToNumericValue(byte c) {

+        if (c >= '0' && c <= '9') {

+            return (byte)(c - '0');

+        } else if (c >= 'A' && c <= 'Z') {

+            return (byte)(0xA + (c - 'A'));

+        } else if (c >= 'a' && c <= 'z') {

+            return (byte)(0xA + (c - 'a'));

+        } else {

+            /*

+             * This should never happen since all calls to this method

+             * are preceded by a check that c is in [0-9A-Za-z]

+             */

+            throw new IllegalArgumentException((char) c 

+                    + " is not a hexadecimal digit");

+        }

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
new file mode 100644
index 0000000..a278341
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
@@ -0,0 +1,72 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Performs Quoted-Printable encoding on an underlying stream.
+ */
+public class QuotedPrintableOutputStream extends FilterOutputStream {
+    
+    private QuotedPrintableEncoder encoder;
+    private boolean closed = false;
+
+    public QuotedPrintableOutputStream(OutputStream out, boolean binary) {
+        super(out);
+        encoder = new QuotedPrintableEncoder(CodecUtil.DEFAULT_ENCODING_BUFFER_SIZE, binary);
+        encoder.initEncoding(out);
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (closed)
+            return;
+
+        try {
+            encoder.completeEncoding();
+            // do not close the wrapped stream
+        } finally {
+            closed = true;
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        encoder.flushOutput();
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        this.write(new byte[] { (byte) b }, 0, 1);
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (closed) {
+            throw new IOException("QuotedPrintableOutputStream has been closed");
+        }
+
+        encoder.encodeChunk(b, off, len);
+    }
+
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java
new file mode 100644
index 0000000..3c08df1
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/codec/UnboundedFifoByteBuffer.java
@@ -0,0 +1,265 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.util.Iterator;

+import java.util.NoSuchElementException;

+

+/**

+ * UnboundedFifoByteBuffer is a very efficient buffer implementation.

+ * According to performance testing, it exhibits a constant access time, but it

+ * also outperforms ArrayList when used for the same purpose.

+ * <p>

+ * The removal order of an <code>UnboundedFifoByteBuffer</code> is based on the insertion

+ * order; elements are removed in the same order in which they were added.

+ * The iteration order is the same as the removal order.

+ * <p>

+ * The {@link #remove()} and {@link #get()} operations perform in constant time.

+ * The {@link #add(Object)} operation performs in amortized constant time.  All

+ * other operations perform in linear time or worse.

+ * <p>

+ * Note that this implementation is not synchronized.  The following can be

+ * used to provide synchronized access to your <code>UnboundedFifoByteBuffer</code>:

+ * <pre>

+ *   Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer());

+ * </pre>

+ * <p>

+ * This buffer prevents null objects from being added.

+ *

+ * @since Commons Collections 3.0 (previously in main package v2.1)

+ */

+class UnboundedFifoByteBuffer {

+

+    protected byte[] buffer;

+    protected int head;

+    protected int tail;

+

+    /**

+     * Constructs an UnboundedFifoByteBuffer with the default number of elements.

+     * It is exactly the same as performing the following:

+     *

+     * <pre>

+     *   new UnboundedFifoByteBuffer(32);

+     * </pre>

+     */

+    public UnboundedFifoByteBuffer() {

+        this(32);

+    }

+

+    /**

+     * Constructs an UnboundedFifoByteBuffer with the specified number of elements.

+     * The integer must be a positive integer.

+     *

+     * @param initialSize  the initial size of the buffer

+     * @throws IllegalArgumentException  if the size is less than 1

+     */

+    public UnboundedFifoByteBuffer(int initialSize) {

+        if (initialSize <= 0) {

+            throw new IllegalArgumentException("The size must be greater than 0");

+        }

+        buffer = new byte[initialSize + 1];

+        head = 0;

+        tail = 0;

+    }

+

+    /**

+     * Returns the number of elements stored in the buffer.

+     *

+     * @return this buffer's size

+     */

+    public int size() {

+        int size = 0;

+

+        if (tail < head) {

+            size = buffer.length - head + tail;

+        } else {

+            size = tail - head;

+        }

+

+        return size;

+    }

+

+    /**

+     * Returns true if this buffer is empty; false otherwise.

+     *

+     * @return true if this buffer is empty

+     */

+    public boolean isEmpty() {

+        return (size() == 0);

+    }

+

+    /**

+     * Adds the given element to this buffer.

+     *

+     * @param b  the byte to add

+     * @return true, always

+     */

+    public boolean add(final byte b) {

+

+        if (size() + 1 >= buffer.length) {

+            byte[] tmp = new byte[((buffer.length - 1) * 2) + 1];

+

+            int j = 0;

+            for (int i = head; i != tail;) {

+                tmp[j] = buffer[i];

+                buffer[i] = 0;

+

+                j++;

+                i++;

+                if (i == buffer.length) {

+                    i = 0;

+                }

+            }

+

+            buffer = tmp;

+            head = 0;

+            tail = j;

+        }

+

+        buffer[tail] = b;

+        tail++;

+        if (tail >= buffer.length) {

+            tail = 0;

+        }

+        return true;

+    }

+

+    /**

+     * Returns the next object in the buffer.

+     *

+     * @return the next object in the buffer

+     * @throws BufferUnderflowException  if this buffer is empty

+     */

+    public byte get() {

+        if (isEmpty()) {

+            throw new IllegalStateException("The buffer is already empty");

+        }

+

+        return buffer[head];

+    }

+

+    /**

+     * Removes the next object from the buffer

+     *

+     * @return the removed object

+     * @throws BufferUnderflowException  if this buffer is empty

+     */

+    public byte remove() {

+        if (isEmpty()) {

+            throw new IllegalStateException("The buffer is already empty");

+        }

+

+        byte element = buffer[head];

+

+        head++;

+        if (head >= buffer.length) {

+            head = 0;

+        }

+

+        return element;

+    }

+

+    /**

+     * Increments the internal index.

+     *

+     * @param index  the index to increment

+     * @return the updated index

+     */

+    private int increment(int index) {

+        index++;

+        if (index >= buffer.length) {

+            index = 0;

+        }

+        return index;

+    }

+

+    /**

+     * Decrements the internal index.

+     *

+     * @param index  the index to decrement

+     * @return the updated index

+     */

+    private int decrement(int index) {

+        index--;

+        if (index < 0) {

+            index = buffer.length - 1;

+        }

+        return index;

+    }

+

+    /**

+     * Returns an iterator over this buffer's elements.

+     *

+     * @return an iterator over this buffer's elements

+     */

+    public Iterator<Byte> iterator() {

+        return new Iterator<Byte>() {

+

+            private int index = head;

+            private int lastReturnedIndex = -1;

+

+            public boolean hasNext() {

+                return index != tail;

+

+            }

+

+            public Byte next() {

+                if (!hasNext()) {

+                    throw new NoSuchElementException();

+                }

+                lastReturnedIndex = index;

+                index = increment(index);

+                return new Byte(buffer[lastReturnedIndex]);

+            }

+

+            public void remove() {

+                if (lastReturnedIndex == -1) {

+                    throw new IllegalStateException();

+                }

+

+                // First element can be removed quickly

+                if (lastReturnedIndex == head) {

+                    UnboundedFifoByteBuffer.this.remove();

+                    lastReturnedIndex = -1;

+                    return;

+                }

+

+                // Other elements require us to shift the subsequent elements

+                int i = lastReturnedIndex + 1;

+                while (i != tail) {

+                    if (i >= buffer.length) {

+                        buffer[i - 1] = buffer[0];

+                        i = 0;

+                    } else {

+                        buffer[i - 1] = buffer[i];

+                        i++;

+                    }

+                }

+

+                lastReturnedIndex = -1;

+                tail = decrement(tail);

+                buffer[tail] = 0;

+                index = decrement(index);

+            }

+

+        };

+    }

+

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java
new file mode 100644
index 0000000..087952e
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/BodyDescriptor.java
@@ -0,0 +1,35 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.descriptor;

+

+/**

+ * Encapsulates the values of the MIME-specific header fields 

+ * (which starts with <code>Content-</code>). 

+ */

+public interface BodyDescriptor extends ContentDescriptor {

+

+    /**

+     * Returns the body descriptors boundary.

+     * @return Boundary string, if known, or null. The latter may be the

+     *   case, in particular, if the body is no multipart entity.

+     */

+    String getBoundary();

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/ContentDescriptor.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/ContentDescriptor.java
new file mode 100644
index 0000000..865468b
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/ContentDescriptor.java
@@ -0,0 +1,88 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.descriptor;
+
+import java.util.Map;
+
+/**
+ * Represents common content properties. 
+ */
+public interface ContentDescriptor {
+
+    /**
+     * Returns the body descriptors MIME type.
+     * @see #getMediaType()
+     * @see #getSubType()
+     * @return The MIME type, which has been parsed from the
+     *   content-type definition. Must not be null, but
+     *   "text/plain", if no content-type was specified.
+     */
+    String getMimeType();
+    
+    /**
+     * Gets the defaulted MIME media type for this content.
+     * For example <code>TEXT</code>, <code>IMAGE</code>, <code>MULTIPART</code>
+     * @see #getMimeType()
+     * @return the MIME media type when content-type specified,
+     * otherwise the correct default (<code>TEXT</code>)
+     */
+    String getMediaType();
+
+    /**
+     * Gets the defaulted MIME sub type for this content.
+     * @see #getMimeType()
+     * @return the MIME media type when content-type is specified,
+     * otherwise the correct default (<code>PLAIN</code>)
+     */
+    String getSubType();
+    
+    /**
+     * <p>The body descriptors character set, defaulted appropriately for the MIME type.</p>
+     * <p>
+     * For <code>TEXT</code> types, this will be defaulted to <code>us-ascii</code>.
+     * For other types, when the charset parameter is missing this property will be null.
+     * </p>
+     * @return Character set, which has been parsed from the
+     *   content-type definition. Not null for <code>TEXT</code> types, when unset will
+     *   be set to default <code>us-ascii</code>. For other types, when unset,
+     *   null will be returned.
+     */
+    String getCharset();
+
+    /**
+     * Returns the body descriptors transfer encoding.
+     * @return The transfer encoding. Must not be null, but "7bit",
+     *   if no transfer-encoding was specified.
+     */
+    String getTransferEncoding();
+
+    /**
+     * Returns the map of parameters of the content-type header.
+     */
+    Map<String, String> getContentTypeParameters();
+
+    /**
+     * Returns the body descriptors content-length.
+     * @return Content length, if known, or -1, to indicate the absence of a
+     *   content-length header.
+     */
+    long getContentLength();
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java
new file mode 100644
index 0000000..12d9f08
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptor.java
@@ -0,0 +1,244 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.descriptor;

+

+import java.util.HashMap;

+import java.util.Map;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.parser.Field;

+import org.apache.james.mime4j.util.MimeUtil;

+

+/**

+ * Encapsulates the values of the MIME-specific header fields 

+ * (which starts with <code>Content-</code>). 

+ */

+public class DefaultBodyDescriptor implements MutableBodyDescriptor {

+    private static final String US_ASCII = "us-ascii";

+

+    private static final String SUB_TYPE_EMAIL = "rfc822";

+

+    private static final String MEDIA_TYPE_TEXT = "text";

+

+    private static final String MEDIA_TYPE_MESSAGE = "message";

+

+    private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;

+

+    private static final String DEFAULT_SUB_TYPE = "plain";

+

+    private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;

+

+    private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;

+

+    private static Log log = LogFactory.getLog(DefaultBodyDescriptor.class);

+    

+    private String mediaType = DEFAULT_MEDIA_TYPE;

+    private String subType = DEFAULT_SUB_TYPE;

+    private String mimeType = DEFAULT_MIME_TYPE;

+    private String boundary = null;

+    private String charset = US_ASCII;

+    private String transferEncoding = "7bit";

+    private Map<String, String> parameters = new HashMap<String, String>();

+    private boolean contentTypeSet;

+    private boolean contentTransferEncSet;

+    private long contentLength = -1;

+    

+    /**

+     * Creates a new root <code>BodyDescriptor</code> instance.

+     */

+    public DefaultBodyDescriptor() {

+        this(null);

+    }

+

+    /**

+     * Creates a new <code>BodyDescriptor</code> instance.

+     * 

+     * @param parent the descriptor of the parent or <code>null</code> if this

+     *        is the root descriptor.

+     */

+    public DefaultBodyDescriptor(BodyDescriptor parent) {

+        if (parent != null && MimeUtil.isSameMimeType("multipart/digest", parent.getMimeType())) {

+            mimeType = EMAIL_MESSAGE_MIME_TYPE;

+            subType = SUB_TYPE_EMAIL;

+            mediaType = MEDIA_TYPE_MESSAGE;

+        } else {

+            mimeType = DEFAULT_MIME_TYPE;

+            subType = DEFAULT_SUB_TYPE;

+            mediaType = DEFAULT_MEDIA_TYPE;

+        }

+    }

+    

+    /**

+     * Should be called for each <code>Content-</code> header field of 

+     * a MIME message or part.

+     * 

+     * @param field the MIME field.

+     */

+    public void addField(Field field) {

+        String name = field.getName();

+        String value = field.getBody();

+

+        name = name.trim().toLowerCase();

+        

+        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {

+            contentTransferEncSet = true;

+            

+            value = value.trim().toLowerCase();

+            if (value.length() > 0) {

+                transferEncoding = value;

+            }

+            

+        } else if (name.equals("content-length") && contentLength == -1) {

+            try {

+                contentLength = Long.parseLong(value.trim());

+            } catch (NumberFormatException e) {

+                log.error("Invalid content-length: " + value);

+            }

+        } else if (name.equals("content-type") && !contentTypeSet) {

+            parseContentType(value);

+        }

+    }

+

+    private void parseContentType(String value) {

+        contentTypeSet = true;

+        

+        Map<String, String> params = MimeUtil.getHeaderParams(value);

+        

+        String main = params.get("");

+        String type = null;

+        String subtype = null;

+        if (main != null) {

+            main = main.toLowerCase().trim();

+            int index = main.indexOf('/');

+            boolean valid = false;

+            if (index != -1) {

+                type = main.substring(0, index).trim();

+                subtype = main.substring(index + 1).trim();

+                if (type.length() > 0 && subtype.length() > 0) {

+                    main = type + "/" + subtype;

+                    valid = true;

+                }

+            }

+            

+            if (!valid) {

+                main = null;

+                type = null;

+                subtype = null;

+            }

+        }

+        String b = params.get("boundary");

+        

+        if (main != null 

+                && ((main.startsWith("multipart/") && b != null) 

+                        || !main.startsWith("multipart/"))) {

+            

+            mimeType = main;

+            this.subType = subtype;

+            this.mediaType = type;

+        }

+        

+        if (MimeUtil.isMultipart(mimeType)) {

+            boundary = b;

+        }

+        

+        String c = params.get("charset");

+        charset = null;

+        if (c != null) {

+            c = c.trim();

+            if (c.length() > 0) {

+                charset = c.toLowerCase();

+            }

+        }

+        if (charset == null && MEDIA_TYPE_TEXT.equals(mediaType)) {

+            charset = US_ASCII;

+        }

+        

+        /*

+         * Add all other parameters to parameters.

+         */

+        parameters.putAll(params);

+        parameters.remove("");

+        parameters.remove("boundary");

+        parameters.remove("charset");

+    }

+

+    /**

+     * Return the MimeType 

+     * 

+     * @return mimeType

+     */

+    public String getMimeType() {

+        return mimeType;

+    }

+    

+    /**

+     * Return the boundary

+     * 

+     * @return boundary

+     */

+    public String getBoundary() {

+        return boundary;

+    }

+    

+    /**

+     * Return the charset

+     * 

+     * @return charset

+     */

+    public String getCharset() {

+        return charset;

+    }

+    

+    /**

+     * Return all parameters for the BodyDescriptor

+     * 

+     * @return parameters

+     */

+    public Map<String, String> getContentTypeParameters() {

+        return parameters;

+    }

+    

+    /**

+     * Return the TransferEncoding

+     * 

+     * @return transferEncoding

+     */

+    public String getTransferEncoding() {

+        return transferEncoding;

+    }

+    

+    @Override

+    public String toString() {

+        return mimeType;

+    }

+

+    public long getContentLength() {

+        return contentLength;

+    }

+

+    public String getMediaType() {

+        return mediaType;

+    }

+

+    public String getSubType() {

+        return subType;

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptor.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptor.java
new file mode 100644
index 0000000..f274829
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptor.java
@@ -0,0 +1,467 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.descriptor;
+
+import java.io.StringReader;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.field.datetime.DateTime;
+import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
+import org.apache.james.mime4j.field.datetime.parser.ParseException;
+import org.apache.james.mime4j.field.language.parser.ContentLanguageParser;
+import org.apache.james.mime4j.field.mimeversion.parser.MimeVersionParser;
+import org.apache.james.mime4j.field.structured.parser.StructuredFieldParser;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * Parses and stores values for standard MIME header values.
+ * 
+ */
+public class MaximalBodyDescriptor extends DefaultBodyDescriptor {
+
+    private static final int DEFAULT_MINOR_VERSION = 0;
+    private static final int DEFAULT_MAJOR_VERSION = 1;
+    private boolean isMimeVersionSet;
+    private int mimeMinorVersion;
+    private int mimeMajorVersion;
+    private MimeException mimeVersionException;
+    private String contentId;
+    private boolean isContentIdSet;
+    private String contentDescription;
+    private boolean isContentDescriptionSet;
+    private String contentDispositionType;
+    private Map<String, String> contentDispositionParameters;
+    private DateTime contentDispositionModificationDate;
+    private MimeException contentDispositionModificationDateParseException;
+    private DateTime contentDispositionCreationDate;
+    private MimeException contentDispositionCreationDateParseException;
+    private DateTime contentDispositionReadDate;
+    private MimeException contentDispositionReadDateParseException;
+    private long contentDispositionSize;
+    private MimeException contentDispositionSizeParseException;
+    private boolean isContentDispositionSet;
+    private List<String> contentLanguage;
+    private MimeException contentLanguageParseException;
+    private boolean isContentLanguageSet;
+    private MimeException contentLocationParseException;
+    private String contentLocation;
+    private boolean isContentLocationSet;
+    private String contentMD5Raw;
+    private boolean isContentMD5Set;
+    
+    protected MaximalBodyDescriptor() {
+        this(null);
+    }
+
+    public MaximalBodyDescriptor(BodyDescriptor parent) {
+        super(parent);
+        isMimeVersionSet = false;
+        mimeMajorVersion = DEFAULT_MAJOR_VERSION;
+        mimeMinorVersion = DEFAULT_MINOR_VERSION;
+        this.contentId = null;
+        this.isContentIdSet = false;
+        this.contentDescription = null;
+        this.isContentDescriptionSet = false;
+        this.contentDispositionType = null;
+        this.contentDispositionParameters = Collections.emptyMap();
+        this.contentDispositionModificationDate = null;
+        this.contentDispositionModificationDateParseException = null;
+        this.contentDispositionCreationDate = null;
+        this.contentDispositionCreationDateParseException = null;
+        this.contentDispositionReadDate = null;
+        this.contentDispositionReadDateParseException = null;
+        this.contentDispositionSize = -1;
+        this.contentDispositionSizeParseException = null;
+        this.isContentDispositionSet = false;
+        this.contentLanguage = null;
+        this.contentLanguageParseException = null;
+        this.isContentIdSet = false;
+        this.contentLocation = null;
+        this.contentLocationParseException = null;
+        this.isContentLocationSet = false;
+        this.contentMD5Raw = null;
+        this.isContentMD5Set = false;
+    }
+    
+    @Override
+    public void addField(Field field) {
+        String name = field.getName();
+        String value = field.getBody();
+        name = name.trim().toLowerCase();
+        if (MimeUtil.MIME_HEADER_MIME_VERSION.equals(name) && !isMimeVersionSet) {
+            parseMimeVersion(value);
+        } else if (MimeUtil.MIME_HEADER_CONTENT_ID.equals(name) && !isContentIdSet) {
+            parseContentId(value);
+        } else if (MimeUtil.MIME_HEADER_CONTENT_DESCRIPTION.equals(name) && !isContentDescriptionSet) {
+            parseContentDescription(value);
+        } else if (MimeUtil.MIME_HEADER_CONTENT_DISPOSITION.equals(name) && !isContentDispositionSet) {
+            parseContentDisposition(value);
+        } else if (MimeUtil.MIME_HEADER_LANGAUGE.equals(name) && !isContentLanguageSet) {
+            parseLanguage(value);
+        } else if (MimeUtil.MIME_HEADER_LOCATION.equals(name) && !isContentLocationSet) {
+            parseLocation(value);
+        } else if (MimeUtil.MIME_HEADER_MD5.equals(name) && !isContentMD5Set) {
+            parseMD5(value);
+        } else {
+            super.addField(field);
+        }
+    }
+    
+    private void parseMD5(String value) {
+        isContentMD5Set = true;
+        if (value != null) {
+            contentMD5Raw = value.trim();
+        }
+    }
+
+    private void parseLocation(final String value) {
+        isContentLocationSet = true;
+        if (value != null) {
+            final StringReader stringReader = new StringReader(value);
+            final StructuredFieldParser parser = new StructuredFieldParser(stringReader);
+            parser.setFoldingPreserved(false);
+            try {
+                contentLocation = parser.parse();
+            } catch (MimeException e) { 
+                contentLocationParseException = e;
+            }
+        }
+    }
+    
+    private void parseLanguage(final String value) {
+        isContentLanguageSet = true;
+        if (value != null) {
+            try {
+                final ContentLanguageParser parser = new ContentLanguageParser(new StringReader(value));
+                contentLanguage = parser.parse();
+            } catch (MimeException e) {
+                contentLanguageParseException = e;
+            }
+        }
+    }
+
+    private void parseContentDisposition(final String value) {
+        isContentDispositionSet = true;
+        contentDispositionParameters = MimeUtil.getHeaderParams(value);
+        contentDispositionType = contentDispositionParameters.get("");
+        
+        final String contentDispositionModificationDate 
+            = contentDispositionParameters.get(MimeUtil.PARAM_MODIFICATION_DATE);
+        if (contentDispositionModificationDate != null) {
+            try {
+                this.contentDispositionModificationDate = parseDate(contentDispositionModificationDate);
+            } catch (ParseException e) {
+                this.contentDispositionModificationDateParseException = e;
+            } 
+        }
+        
+        final String contentDispositionCreationDate 
+            = contentDispositionParameters.get(MimeUtil.PARAM_CREATION_DATE);
+        if (contentDispositionCreationDate != null) {
+            try {
+                this.contentDispositionCreationDate = parseDate(contentDispositionCreationDate);
+            } catch (ParseException e) {
+                this.contentDispositionCreationDateParseException = e;
+            }         
+        }
+        
+        final String contentDispositionReadDate 
+            = contentDispositionParameters.get(MimeUtil.PARAM_READ_DATE);
+        if (contentDispositionReadDate != null) {
+            try {
+                this.contentDispositionReadDate = parseDate(contentDispositionReadDate);
+            } catch (ParseException e) {
+                this.contentDispositionReadDateParseException = e;
+            }         
+        }
+        
+        final String size = contentDispositionParameters.get(MimeUtil.PARAM_SIZE);
+        if (size != null) {
+            try {
+                contentDispositionSize = Long.parseLong(size);
+            } catch (NumberFormatException e) {
+                this.contentDispositionSizeParseException = (MimeException) new MimeException(e.getMessage(), e).fillInStackTrace();
+            }
+        }
+        contentDispositionParameters.remove("");
+    }
+
+    private DateTime parseDate(final String date) throws ParseException {
+        final StringReader stringReader = new StringReader(date);
+        final DateTimeParser parser = new DateTimeParser(stringReader);
+        DateTime result = parser.date_time();
+        return result;
+    }
+    
+    private void parseContentDescription(String value) {
+        if (value == null) {
+            contentDescription = "";
+        } else {
+            contentDescription = value.trim();
+        }
+        isContentDescriptionSet = true;
+    }
+
+    private void parseContentId(final String value) {
+        if (value == null) {
+            contentId = "";
+        } else {
+            contentId = value.trim();
+        }
+        isContentIdSet = true;
+    }
+
+    private void parseMimeVersion(String value) {
+        final StringReader reader = new StringReader(value);
+        final MimeVersionParser parser = new MimeVersionParser(reader);
+        try {
+            parser.parse();
+            final int major = parser.getMajorVersion();
+            if (major != MimeVersionParser.INITIAL_VERSION_VALUE) {
+                mimeMajorVersion = major;
+            }
+            final int minor = parser.getMinorVersion();
+            if (minor != MimeVersionParser.INITIAL_VERSION_VALUE) {
+                mimeMinorVersion = minor;
+            }
+        } catch (MimeException e) {
+            this.mimeVersionException = e;
+        }
+        isMimeVersionSet = true;
+    }
+    
+    /**
+     * Gets the MIME major version
+     * as specified by the <code>MIME-Version</code>
+     * header.
+     * Defaults to one.
+     * @return positive integer
+     */
+    public int getMimeMajorVersion() {
+        return mimeMajorVersion;
+    }
+    
+    /**
+     * Gets the MIME minor version
+     * as specified by the <code>MIME-Version</code>
+     * header. 
+     * Defaults to zero.
+     * @return positive integer
+     */
+    public int getMimeMinorVersion() {
+        return mimeMinorVersion;
+    }
+    
+
+    /**
+     * When the MIME version header exists but cannot be parsed
+     * this field will be contain the exception.
+     * @return <code>MimeException</code> if the mime header cannot
+     * be parsed, null otherwise
+     */
+    public MimeException getMimeVersionParseException() {
+        return mimeVersionException;
+    }
+    
+    /**
+     * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a> 
+     * <code>Content-Description</code> header.
+     * @return value of the <code>Content-Description</code> when present,
+     * null otherwise
+     */
+    public String getContentDescription() {
+        return contentDescription;
+    }
+    
+    /**
+     * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a> 
+     * <code>Content-ID</code> header.
+     * @return value of the <code>Content-ID</code> when present,
+     * null otherwise
+     */
+    public String getContentId() {
+        return contentId;
+    }
+    
+    /**
+     * Gets the disposition type of the <code>content-disposition</code> field.
+     * The value is case insensitive and will be converted to lower case.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return content disposition type, 
+     * or null when this has not been set
+     */
+    public String getContentDispositionType() {
+        return contentDispositionType;
+    }
+    
+    /**
+     * Gets the parameters of the <code>content-disposition</code> field.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return parameter value strings indexed by parameter name strings,
+     * not null
+     */
+    public Map<String, String> getContentDispositionParameters() {
+        return contentDispositionParameters;
+    }
+    
+    /**
+     * Gets the <code>filename</code> parameter value of the <code>content-disposition</code> field.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return filename parameter value, 
+     * or null when it is not present
+     */
+    public String getContentDispositionFilename() {
+        return contentDispositionParameters.get(MimeUtil.PARAM_FILENAME);
+    }
+    
+    /**
+     * Gets the <code>modification-date</code> parameter value of the <code>content-disposition</code> field.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return modification-date parameter value,
+     * or null when this is not present
+     */
+    public DateTime getContentDispositionModificationDate() {
+        return contentDispositionModificationDate;
+    }
+    
+    /**
+     * Gets any exception thrown during the parsing of {@link #getContentDispositionModificationDate()}
+     * @return <code>ParseException</code> when the modification-date parse fails,
+     * null otherwise
+     */
+    public MimeException getContentDispositionModificationDateParseException() {
+        return contentDispositionModificationDateParseException;
+    }
+    
+    /**
+     * Gets the <code>creation-date</code> parameter value of the <code>content-disposition</code> field.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return creation-date parameter value,
+     * or null when this is not present
+     */
+    public DateTime getContentDispositionCreationDate() {
+        return contentDispositionCreationDate;
+    }
+    
+    /**
+     * Gets any exception thrown during the parsing of {@link #getContentDispositionCreationDate()}
+     * @return <code>ParseException</code> when the creation-date parse fails,
+     * null otherwise
+     */
+    public MimeException getContentDispositionCreationDateParseException() {
+        return contentDispositionCreationDateParseException;
+    }
+    
+    /**
+     * Gets the <code>read-date</code> parameter value of the <code>content-disposition</code> field.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return read-date parameter value,
+     * or null when this is not present
+     */
+    public DateTime getContentDispositionReadDate() {
+        return contentDispositionReadDate;
+    }
+    
+    /**
+     * Gets any exception thrown during the parsing of {@link #getContentDispositionReadDate()}
+     * @return <code>ParseException</code> when the read-date parse fails,
+     * null otherwise
+     */
+    public MimeException getContentDispositionReadDateParseException() {
+        return contentDispositionReadDateParseException;
+    }
+    
+    /**
+     * Gets the <code>size</code> parameter value of the <code>content-disposition</code> field.
+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
+     * @return size parameter value,
+     * or -1 if this size has not been set
+     */
+    public long getContentDispositionSize() {
+        return contentDispositionSize;
+    }
+    
+    /**
+     * Gets any exception thrown during the parsing of {@link #getContentDispositionSize()}
+     * @return <code>ParseException</code> when the read-date parse fails,
+     * null otherwise
+     */
+    public MimeException getContentDispositionSizeParseException() {
+        return contentDispositionSizeParseException;
+    }
+    
+    /**
+     * Get the <code>content-language</code> header values.
+     * Each applicable language tag will be returned in order.
+     * See <a href='http://tools.ietf.org/html/rfc4646'>RFC4646</a> 
+     * <cite>http://tools.ietf.org/html/rfc4646</cite>.
+     * @return list of language tag Strings,
+     * or null if no header exists
+     */
+    public List<String> getContentLanguage() {
+        return contentLanguage;
+    }
+
+    /**
+     * Gets any exception thrown during the parsing of {@link #getContentLanguage()}
+     * @return <code>ParseException</code> when the content-language parse fails,
+     * null otherwise
+     */
+    public MimeException getContentLanguageParseException() {
+        return contentLanguageParseException;
+    }
+    
+
+    /**
+     * Get the <code>content-location</code> header value.
+     * See <a href='http://tools.ietf.org/html/rfc2557'>RFC2557</a> 
+     * @return the URL content-location
+     * or null if no header exists
+     */
+    public String getContentLocation() {
+        return contentLocation;
+    }
+    
+    /**
+     * Gets any exception thrown during the parsing of {@link #getContentLocation()}
+     * @return <code>ParseException</code> when the content-language parse fails,
+     * null otherwise
+     */
+    public MimeException getContentLocationParseException() {
+        return contentLocationParseException;
+    }
+    
+    /**
+     * Gets the raw, Base64 encoded value of the
+     * <code>Content-MD5</code> field.
+     * See <a href='http://tools.ietf.org/html/rfc1864'>RFC1864</a>.
+     * @return raw encoded content-md5
+     * or null if no header exists
+     */
+    public String getContentMD5Raw() {
+        return contentMD5Raw;
+    }
+    
+    
+} 
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/MutableBodyDescriptor.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/MutableBodyDescriptor.java
new file mode 100644
index 0000000..8589963
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/descriptor/MutableBodyDescriptor.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+
+package org.apache.james.mime4j.descriptor;
+
+import org.apache.james.mime4j.parser.Field;
+
+/**
+ * Adds mutator.
+ */
+public interface MutableBodyDescriptor extends BodyDescriptor {
+
+    /**
+     * Adds a field to the body descriptor.
+     * @param field the MIME field.
+     */
+    void addField(Field field);
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/AbstractField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/AbstractField.java
new file mode 100644
index 0000000..597c156
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/AbstractField.java
@@ -0,0 +1,174 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * The base class of all field classes.
+ */
+public abstract class AbstractField implements ParsedField {
+
+    private static final Pattern FIELD_NAME_PATTERN = Pattern
+            .compile("^([\\x21-\\x39\\x3b-\\x7e]+):");
+
+    private static final DefaultFieldParser parser = new DefaultFieldParser();
+    
+    private final String name;
+    private final String body;
+    private final ByteSequence raw;
+    
+    protected AbstractField(final String name, final String body, final ByteSequence raw) {
+        this.name = name;
+        this.body = body;
+        this.raw = raw;
+    }
+
+    /**
+     * Parses the given byte sequence and returns an instance of the
+     * <code>Field</code> class. The type of the class returned depends on the
+     * field name; see {@link #parse(String)} for a table of field names and
+     * their corresponding classes.
+     * 
+     * @param raw the bytes to parse.
+     * @return a <code>ParsedField</code> instance.
+     * @throws MimeException if the raw string cannot be split into field name and body.
+     * @see #isValidField()
+     */
+    public static ParsedField parse(final ByteSequence raw) throws MimeException {
+        String rawStr = ContentUtil.decode(raw);
+        return parse(raw, rawStr);
+    }
+
+    /**
+     * Parses the given string and returns an instance of the 
+     * <code>Field</code> class. The type of the class returned depends on
+     * the field name:
+     * <p>
+     * <table>
+     *   <tr><th>Class returned</th><th>Field names</th></tr>
+     *   <tr><td>{@link ContentTypeField}</td><td>Content-Type</td></tr>
+     *   <tr><td>{@link ContentTransferEncodingField}</td><td>Content-Transfer-Encoding</td></tr>
+     *   <tr><td>{@link ContentDispositionField}</td><td>Content-Disposition</td></tr>
+     *   <tr><td>{@link DateTimeField}</td><td>Date, Resent-Date</td></tr>
+     *   <tr><td>{@link MailboxField}</td><td>Sender, Resent-Sender</td></tr>
+     *   <tr><td>{@link MailboxListField}</td><td>From, Resent-From</td></tr>
+     *   <tr><td>{@link AddressListField}</td><td>To, Cc, Bcc, Reply-To, Resent-To, Resent-Cc, Resent-Bcc</td></tr>
+     *   <tr><td>{@link UnstructuredField}</td><td>Subject and others</td></tr>
+     * </table>
+     * 
+     * @param rawStr the string to parse.
+     * @return a <code>ParsedField</code> instance.
+     * @throws MimeException if the raw string cannot be split into field name and body.
+     * @see #isValidField()
+     */
+    public static ParsedField parse(final String rawStr) throws MimeException {
+        ByteSequence raw = ContentUtil.encode(rawStr);
+        return parse(raw, rawStr);
+    }
+
+    /**
+     * Gets the default parser used to parse fields.
+     * 
+     * @return the default field parser
+     */
+    public static DefaultFieldParser getParser() {
+        return parser;
+    }
+    
+    /**
+     * Gets the name of the field (<code>Subject</code>, 
+     * <code>From</code>, etc).
+     * 
+     * @return the field name.
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * Gets the original raw field string.
+     * 
+     * @return the original raw field string.
+     */
+    public ByteSequence getRaw() {
+        return raw;
+    }
+    
+    /**
+     * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field 
+     * body string.
+     * 
+     * @return the unfolded unparsed field body string.
+     */
+    public String getBody() {
+        return body;
+    }
+
+    /**
+     * @see ParsedField#isValidField() 
+     */
+    public boolean isValidField() {
+        return getParseException() == null;
+    }
+
+    /**
+     * @see ParsedField#getParseException() 
+     */
+    public ParseException getParseException() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return name + ": " + body;
+    }
+
+    private static ParsedField parse(final ByteSequence raw, final String rawStr)
+            throws MimeException {
+        /*
+         * Unfold the field.
+         */
+        final String unfolded = MimeUtil.unfold(rawStr);
+
+        /*
+         * Split into name and value.
+         */
+        final Matcher fieldMatcher = FIELD_NAME_PATTERN.matcher(unfolded);
+        if (!fieldMatcher.find()) {
+            throw new MimeException("Invalid field in string");
+        }
+        final String name = fieldMatcher.group(1);
+
+        String body = unfolded.substring(fieldMatcher.end());
+        if (body.length() > 0 && body.charAt(0) == ' ') {
+            body = body.substring(1);
+        }
+
+        return parser.parse(name, body, raw);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/AddressListField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/AddressListField.java
new file mode 100644
index 0000000..f184ebb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/AddressListField.java
@@ -0,0 +1,79 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.field.address.AddressList;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Address list field such as <code>To</code> or <code>Reply-To</code>.

+ */

+public class AddressListField extends AbstractField {

+    private static Log log = LogFactory.getLog(AddressListField.class);

+

+    private boolean parsed = false;

+

+    private AddressList addressList;

+    private ParseException parseException;

+

+    AddressListField(String name, String body, ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    public AddressList getAddressList() {

+        if (!parsed)

+            parse();

+

+        return addressList;

+    }

+

+    @Override

+    public ParseException getParseException() {

+        if (!parsed)

+            parse();

+

+        return parseException;

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        try {

+            addressList = AddressList.parse(body);

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = e;

+        }

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new AddressListField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentDispositionField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentDispositionField.java
new file mode 100644
index 0000000..4a97c36
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentDispositionField.java
@@ -0,0 +1,326 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import java.io.StringReader;

+import java.util.Collections;

+import java.util.Date;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Locale;

+import java.util.Map;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.field.contentdisposition.parser.ContentDispositionParser;

+import org.apache.james.mime4j.field.contentdisposition.parser.TokenMgrError;

+import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Represents a <code>Content-Disposition</code> field.

+ */

+public class ContentDispositionField extends AbstractField {

+    private static Log log = LogFactory.getLog(ContentDispositionField.class);

+

+    /** The <code>inline</code> disposition type. */

+    public static final String DISPOSITION_TYPE_INLINE = "inline";

+

+    /** The <code>attachment</code> disposition type. */

+    public static final String DISPOSITION_TYPE_ATTACHMENT = "attachment";

+

+    /** The name of the <code>filename</code> parameter. */

+    public static final String PARAM_FILENAME = "filename";

+

+    /** The name of the <code>creation-date</code> parameter. */

+    public static final String PARAM_CREATION_DATE = "creation-date";

+

+    /** The name of the <code>modification-date</code> parameter. */

+    public static final String PARAM_MODIFICATION_DATE = "modification-date";

+

+    /** The name of the <code>read-date</code> parameter. */

+    public static final String PARAM_READ_DATE = "read-date";

+

+    /** The name of the <code>size</code> parameter. */

+    public static final String PARAM_SIZE = "size";

+

+    private boolean parsed = false;

+

+    private String dispositionType = "";

+    private Map<String, String> parameters = new HashMap<String, String>();

+    private ParseException parseException;

+

+    private boolean creationDateParsed;

+    private Date creationDate;

+

+    private boolean modificationDateParsed;

+    private Date modificationDate;

+

+    private boolean readDateParsed;

+    private Date readDate;

+

+    ContentDispositionField(String name, String body, ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    /**

+     * Gets the exception that was raised during parsing of the field value, if

+     * any; otherwise, null.

+     */

+    @Override

+    public ParseException getParseException() {

+        if (!parsed)

+            parse();

+

+        return parseException;

+    }

+

+    /**

+     * Gets the disposition type defined in this Content-Disposition field.

+     * 

+     * @return the disposition type or an empty string if not set.

+     */

+    public String getDispositionType() {

+        if (!parsed)

+            parse();

+

+        return dispositionType;

+    }

+

+    /**

+     * Gets the value of a parameter. Parameter names are case-insensitive.

+     * 

+     * @param name

+     *            the name of the parameter to get.

+     * @return the parameter value or <code>null</code> if not set.

+     */

+    public String getParameter(String name) {

+        if (!parsed)

+            parse();

+

+        return parameters.get(name.toLowerCase());

+    }

+

+    /**

+     * Gets all parameters.

+     * 

+     * @return the parameters.

+     */

+    public Map<String, String> getParameters() {

+        if (!parsed)

+            parse();

+

+        return Collections.unmodifiableMap(parameters);

+    }

+

+    /**

+     * Determines if the disposition type of this field matches the given one.

+     * 

+     * @param dispositionType

+     *            the disposition type to match against.

+     * @return <code>true</code> if the disposition type of this field

+     *         matches, <code>false</code> otherwise.

+     */

+    public boolean isDispositionType(String dispositionType) {

+        if (!parsed)

+            parse();

+

+        return this.dispositionType.equalsIgnoreCase(dispositionType);

+    }

+

+    /**

+     * Return <code>true</code> if the disposition type of this field is

+     * <i>inline</i>, <code>false</code> otherwise.

+     * 

+     * @return <code>true</code> if the disposition type of this field is

+     *         <i>inline</i>, <code>false</code> otherwise.

+     */

+    public boolean isInline() {

+        if (!parsed)

+            parse();

+

+        return dispositionType.equals(DISPOSITION_TYPE_INLINE);

+    }

+

+    /**

+     * Return <code>true</code> if the disposition type of this field is

+     * <i>attachment</i>, <code>false</code> otherwise.

+     * 

+     * @return <code>true</code> if the disposition type of this field is

+     *         <i>attachment</i>, <code>false</code> otherwise.

+     */

+    public boolean isAttachment() {

+        if (!parsed)

+            parse();

+

+        return dispositionType.equals(DISPOSITION_TYPE_ATTACHMENT);

+    }

+

+    /**

+     * Gets the value of the <code>filename</code> parameter if set.

+     * 

+     * @return the <code>filename</code> parameter value or <code>null</code>

+     *         if not set.

+     */

+    public String getFilename() {

+        return getParameter(PARAM_FILENAME);

+    }

+

+    /**

+     * Gets the value of the <code>creation-date</code> parameter if set and

+     * valid.

+     * 

+     * @return the <code>creation-date</code> parameter value or

+     *         <code>null</code> if not set or invalid.

+     */

+    public Date getCreationDate() {

+        if (!creationDateParsed) {

+            creationDate = parseDate(PARAM_CREATION_DATE);

+            creationDateParsed = true;

+        }

+

+        return creationDate;

+    }

+

+    /**

+     * Gets the value of the <code>modification-date</code> parameter if set

+     * and valid.

+     * 

+     * @return the <code>modification-date</code> parameter value or

+     *         <code>null</code> if not set or invalid.

+     */

+    public Date getModificationDate() {

+        if (!modificationDateParsed) {

+            modificationDate = parseDate(PARAM_MODIFICATION_DATE);

+            modificationDateParsed = true;

+        }

+

+        return modificationDate;

+    }

+

+    /**

+     * Gets the value of the <code>read-date</code> parameter if set and

+     * valid.

+     * 

+     * @return the <code>read-date</code> parameter value or <code>null</code>

+     *         if not set or invalid.

+     */

+    public Date getReadDate() {

+        if (!readDateParsed) {

+            readDate = parseDate(PARAM_READ_DATE);

+            readDateParsed = true;

+        }

+

+        return readDate;

+    }

+

+    /**

+     * Gets the value of the <code>size</code> parameter if set and valid.

+     * 

+     * @return the <code>size</code> parameter value or <code>-1</code> if

+     *         not set or invalid.

+     */

+    public long getSize() {

+        String value = getParameter(PARAM_SIZE);

+        if (value == null)

+            return -1;

+

+        try {

+            long size = Long.parseLong(value);

+            return size < 0 ? -1 : size;

+        } catch (NumberFormatException e) {

+            return -1;

+        }

+    }

+

+    private Date parseDate(String paramName) {

+        String value = getParameter(paramName);

+        if (value == null) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing " + paramName + " null");

+            }

+            return null;

+        }

+

+        try {

+            return new DateTimeParser(new StringReader(value)).parseAll()

+                    .getDate();

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing " + paramName + " '" + value + "': "

+                        + e.getMessage());

+            }

+            return null;

+        } catch (org.apache.james.mime4j.field.datetime.parser.TokenMgrError e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing " + paramName + " '" + value + "': "

+                        + e.getMessage());

+            }

+            return null;

+        }

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        ContentDispositionParser parser = new ContentDispositionParser(

+                new StringReader(body));

+        try {

+            parser.parseAll();

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = e;

+        } catch (TokenMgrError e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = new ParseException(e.getMessage());

+        }

+

+        final String dispositionType = parser.getDispositionType();

+

+        if (dispositionType != null) {

+            this.dispositionType = dispositionType.toLowerCase(Locale.US);

+

+            List<String> paramNames = parser.getParamNames();

+            List<String> paramValues = parser.getParamValues();

+

+            if (paramNames != null && paramValues != null) {

+                final int len = Math.min(paramNames.size(), paramValues.size());

+                for (int i = 0; i < len; i++) {

+                    String paramName = paramNames.get(i).toLowerCase(Locale.US);

+                    String paramValue = paramValues.get(i);

+                    parameters.put(paramName, paramValue);

+                }

+            }

+        }

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new ContentDispositionField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentTransferEncodingField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentTransferEncodingField.java
new file mode 100644
index 0000000..9459aa0
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentTransferEncodingField.java
@@ -0,0 +1,65 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.util.ByteSequence;

+import org.apache.james.mime4j.util.MimeUtil;

+

+/**

+ * Represents a <code>Content-Transfer-Encoding</code> field.

+ */

+public class ContentTransferEncodingField extends AbstractField {

+    private String encoding;

+

+    ContentTransferEncodingField(String name, String body, ByteSequence raw) {

+        super(name, body, raw);

+        encoding = body.trim().toLowerCase();

+    }

+

+    /**

+     * Gets the encoding defined in this field.

+     * 

+     * @return the encoding or an empty string if not set.

+     */

+    public String getEncoding() {

+        return encoding;

+    }

+

+    /**

+     * Gets the encoding of the given field if. Returns the default

+     * <code>7bit</code> if not set or if <code>f</code> is

+     * <code>null</code>.

+     * 

+     * @return the encoding.

+     */

+    public static String getEncoding(ContentTransferEncodingField f) {

+        if (f != null && f.getEncoding().length() != 0) {

+            return f.getEncoding();

+        }

+        return MimeUtil.ENC_7BIT;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new ContentTransferEncodingField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentTypeField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentTypeField.java
new file mode 100644
index 0000000..a88f675
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ContentTypeField.java
@@ -0,0 +1,258 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import java.io.StringReader;

+import java.util.Collections;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser;

+import org.apache.james.mime4j.field.contenttype.parser.ParseException;

+import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Represents a <code>Content-Type</code> field.

+ */

+public class ContentTypeField extends AbstractField {

+    private static Log log = LogFactory.getLog(ContentTypeField.class);

+

+    /** The prefix of all <code>multipart</code> MIME types. */

+    public static final String TYPE_MULTIPART_PREFIX = "multipart/";

+

+    /** The <code>multipart/digest</code> MIME type. */

+    public static final String TYPE_MULTIPART_DIGEST = "multipart/digest";

+

+    /** The <code>text/plain</code> MIME type. */

+    public static final String TYPE_TEXT_PLAIN = "text/plain";

+

+    /** The <code>message/rfc822</code> MIME type. */

+    public static final String TYPE_MESSAGE_RFC822 = "message/rfc822";

+

+    /** The name of the <code>boundary</code> parameter. */

+    public static final String PARAM_BOUNDARY = "boundary";

+

+    /** The name of the <code>charset</code> parameter. */

+    public static final String PARAM_CHARSET = "charset";

+

+    private boolean parsed = false;

+

+    private String mimeType = "";

+    private Map<String, String> parameters = new HashMap<String, String>();

+    private ParseException parseException;

+

+    ContentTypeField(String name, String body, ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    /**

+     * Gets the exception that was raised during parsing of the field value, if

+     * any; otherwise, null.

+     */

+    @Override

+    public ParseException getParseException() {

+        if (!parsed)

+            parse();

+

+        return parseException;

+    }

+

+    /**

+     * Gets the MIME type defined in this Content-Type field.

+     * 

+     * @return the MIME type or an empty string if not set.

+     */

+    public String getMimeType() {

+        if (!parsed)

+            parse();

+

+        return mimeType;

+    }

+

+    /**

+     * Gets the value of a parameter. Parameter names are case-insensitive.

+     * 

+     * @param name

+     *            the name of the parameter to get.

+     * @return the parameter value or <code>null</code> if not set.

+     */

+    public String getParameter(String name) {

+        if (!parsed)

+            parse();

+

+        return parameters.get(name.toLowerCase());

+    }

+

+    /**

+     * Gets all parameters.

+     * 

+     * @return the parameters.

+     */

+    public Map<String, String> getParameters() {

+        if (!parsed)

+            parse();

+

+        return Collections.unmodifiableMap(parameters);

+    }

+

+    /**

+     * Determines if the MIME type of this field matches the given one.

+     * 

+     * @param mimeType

+     *            the MIME type to match against.

+     * @return <code>true</code> if the MIME type of this field matches,

+     *         <code>false</code> otherwise.

+     */

+    public boolean isMimeType(String mimeType) {

+        if (!parsed)

+            parse();

+

+        return this.mimeType.equalsIgnoreCase(mimeType);

+    }

+

+    /**

+     * Determines if the MIME type of this field is <code>multipart/*</code>.

+     * 

+     * @return <code>true</code> if this field is has a

+     *         <code>multipart/*</code> MIME type, <code>false</code>

+     *         otherwise.

+     */

+    public boolean isMultipart() {

+        if (!parsed)

+            parse();

+

+        return mimeType.startsWith(TYPE_MULTIPART_PREFIX);

+    }

+

+    /**

+     * Gets the value of the <code>boundary</code> parameter if set.

+     * 

+     * @return the <code>boundary</code> parameter value or <code>null</code>

+     *         if not set.

+     */

+    public String getBoundary() {

+        return getParameter(PARAM_BOUNDARY);

+    }

+

+    /**

+     * Gets the value of the <code>charset</code> parameter if set.

+     * 

+     * @return the <code>charset</code> parameter value or <code>null</code>

+     *         if not set.

+     */

+    public String getCharset() {

+        return getParameter(PARAM_CHARSET);

+    }

+

+    /**

+     * Gets the MIME type defined in the child's Content-Type field or derives a

+     * MIME type from the parent if child is <code>null</code> or hasn't got a

+     * MIME type value set. If child's MIME type is multipart but no boundary

+     * has been set the MIME type of child will be derived from the parent.

+     * 

+     * @param child

+     *            the child.

+     * @param parent

+     *            the parent.

+     * @return the MIME type.

+     */

+    public static String getMimeType(ContentTypeField child,

+            ContentTypeField parent) {

+        if (child == null || child.getMimeType().length() == 0

+                || child.isMultipart() && child.getBoundary() == null) {

+

+            if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) {

+                return TYPE_MESSAGE_RFC822;

+            } else {

+                return TYPE_TEXT_PLAIN;

+            }

+        }

+

+        return child.getMimeType();

+    }

+

+    /**

+     * Gets the value of the <code>charset</code> parameter if set for the

+     * given field. Returns the default <code>us-ascii</code> if not set or if

+     * <code>f</code> is <code>null</code>.

+     * 

+     * @return the <code>charset</code> parameter value.

+     */

+    public static String getCharset(ContentTypeField f) {

+        if (f != null) {

+            String charset = f.getCharset();

+            if (charset != null && charset.length() > 0) {

+                return charset;

+            }

+        }

+        return "us-ascii";

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        ContentTypeParser parser = new ContentTypeParser(new StringReader(body));

+        try {

+            parser.parseAll();

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = e;

+        } catch (TokenMgrError e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = new ParseException(e.getMessage());

+        }

+

+        final String type = parser.getType();

+        final String subType = parser.getSubType();

+

+        if (type != null && subType != null) {

+            mimeType = (type + "/" + subType).toLowerCase();

+

+            List<String> paramNames = parser.getParamNames();

+            List<String> paramValues = parser.getParamValues();

+

+            if (paramNames != null && paramValues != null) {

+                final int len = Math.min(paramNames.size(), paramValues.size());

+                for (int i = 0; i < len; i++) {

+                    String paramName = paramNames.get(i).toLowerCase();

+                    String paramValue = paramValues.get(i);

+                    parameters.put(paramName, paramValue);

+                }

+            }

+        }

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new ContentTypeField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DateTimeField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DateTimeField.java
new file mode 100644
index 0000000..0e0f5eb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DateTimeField.java
@@ -0,0 +1,89 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import java.io.StringReader;

+import java.util.Date;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;

+import org.apache.james.mime4j.field.datetime.parser.ParseException;

+import org.apache.james.mime4j.field.datetime.parser.TokenMgrError;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Date-time field such as <code>Date</code> or <code>Resent-Date</code>.

+ */

+public class DateTimeField extends AbstractField {

+    private static Log log = LogFactory.getLog(DateTimeField.class);

+

+    private boolean parsed = false;

+

+    private Date date;

+    private ParseException parseException;

+

+    DateTimeField(String name, String body, ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    public Date getDate() {

+        if (!parsed)

+            parse();

+

+        return date;

+    }

+

+    @Override

+    public ParseException getParseException() {

+        if (!parsed)

+            parse();

+

+        return parseException;

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        try {

+            date = new DateTimeParser(new StringReader(body)).parseAll()

+                    .getDate();

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = e;

+        } catch (TokenMgrError e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = new ParseException(e.getMessage());

+        }

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new DateTimeField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java
new file mode 100644
index 0000000..edb70c7
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DefaultFieldParser.java
@@ -0,0 +1,53 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+public class DefaultFieldParser extends DelegatingFieldParser {

+

+    public DefaultFieldParser() {

+        setFieldParser(FieldName.CONTENT_TRANSFER_ENCODING,

+                ContentTransferEncodingField.PARSER);

+        setFieldParser(FieldName.CONTENT_TYPE, ContentTypeField.PARSER);

+        setFieldParser(FieldName.CONTENT_DISPOSITION,

+                ContentDispositionField.PARSER);

+

+        final FieldParser dateTimeParser = DateTimeField.PARSER;

+        setFieldParser(FieldName.DATE, dateTimeParser);

+        setFieldParser(FieldName.RESENT_DATE, dateTimeParser);

+

+        final FieldParser mailboxListParser = MailboxListField.PARSER;

+        setFieldParser(FieldName.FROM, mailboxListParser);

+        setFieldParser(FieldName.RESENT_FROM, mailboxListParser);

+

+        final FieldParser mailboxParser = MailboxField.PARSER;

+        setFieldParser(FieldName.SENDER, mailboxParser);

+        setFieldParser(FieldName.RESENT_SENDER, mailboxParser);

+

+        final FieldParser addressListParser = AddressListField.PARSER;

+        setFieldParser(FieldName.TO, addressListParser);

+        setFieldParser(FieldName.RESENT_TO, addressListParser);

+        setFieldParser(FieldName.CC, addressListParser);

+        setFieldParser(FieldName.RESENT_CC, addressListParser);

+        setFieldParser(FieldName.BCC, addressListParser);

+        setFieldParser(FieldName.RESENT_BCC, addressListParser);

+        setFieldParser(FieldName.REPLY_TO, addressListParser);

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java
new file mode 100644
index 0000000..eccf883
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/DelegatingFieldParser.java
@@ -0,0 +1,53 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import java.util.HashMap;

+import java.util.Map;

+

+import org.apache.james.mime4j.util.ByteSequence;

+

+public class DelegatingFieldParser implements FieldParser {

+    

+    private Map<String, FieldParser> parsers = new HashMap<String, FieldParser>();

+    private FieldParser defaultParser = UnstructuredField.PARSER;

+    

+    /**

+     * Sets the parser used for the field named <code>name</code>.

+     * @param name the name of the field

+     * @param parser the parser for fields named <code>name</code>

+     */

+    public void setFieldParser(final String name, final FieldParser parser) {

+        parsers.put(name.toLowerCase(), parser);

+    }

+    

+    public FieldParser getParser(final String name) {

+        final FieldParser field = parsers.get(name.toLowerCase());

+        if(field==null) {

+            return defaultParser;

+        }

+        return field;

+    }

+    

+    public ParsedField parse(final String name, final String body, final ByteSequence raw) {

+        final FieldParser parser = getParser(name);

+        return parser.parse(name, body, raw);

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/FieldName.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/FieldName.java
new file mode 100644
index 0000000..d4cff53
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/FieldName.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+/**
+ * Constants for common header field names.
+ */
+public class FieldName {
+
+    public static final String CONTENT_DISPOSITION = "Content-Disposition";
+    public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+    public static final String CONTENT_TYPE = "Content-Type";
+
+    public static final String DATE = "Date";
+    public static final String MESSAGE_ID = "Message-ID";
+    public static final String SUBJECT = "Subject";
+
+    public static final String FROM = "From";
+    public static final String SENDER = "Sender";
+    public static final String TO = "To";
+    public static final String CC = "Cc";
+    public static final String BCC = "Bcc";
+    public static final String REPLY_TO = "Reply-To";
+
+    public static final String RESENT_DATE = "Resent-Date";
+
+    public static final String RESENT_FROM = "Resent-From";
+    public static final String RESENT_SENDER = "Resent-Sender";
+    public static final String RESENT_TO = "Resent-To";
+    public static final String RESENT_CC = "Resent-Cc";
+    public static final String RESENT_BCC = "Resent-Bcc";
+
+    private FieldName() {
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/FieldParser.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/FieldParser.java
new file mode 100644
index 0000000..0816642
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/FieldParser.java
@@ -0,0 +1,28 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.util.ByteSequence;

+

+public interface FieldParser {

+    

+    ParsedField parse(final String name, final String body, final ByteSequence raw);

+    

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/Fields.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/Fields.java
new file mode 100644
index 0000000..bfbcf44
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/Fields.java
@@ -0,0 +1,630 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.field.address.Address;
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * Factory for concrete {@link Field} instances.
+ */
+public class Fields {
+
+    private static final Pattern FIELD_NAME_PATTERN = Pattern
+            .compile("[\\x21-\\x39\\x3b-\\x7e]+");
+
+    private Fields() {
+    }
+
+    /**
+     * Creates a <i>Content-Type</i> field from the specified raw field value.
+     * The specified string gets folded into a multiple-line representation if
+     * necessary but is otherwise taken as is.
+     * 
+     * @param contentType
+     *            raw content type containing a MIME type and optional
+     *            parameters.
+     * @return the newly created <i>Content-Type</i> field.
+     */
+    public static ContentTypeField contentType(String contentType) {
+        return parse(ContentTypeField.PARSER, FieldName.CONTENT_TYPE,
+                contentType);
+    }
+
+    /**
+     * Creates a <i>Content-Type</i> field from the specified MIME type and
+     * parameters.
+     * 
+     * @param mimeType
+     *            a MIME type (such as <code>&quot;text/plain&quot;</code> or
+     *            <code>&quot;application/octet-stream&quot;</code>).
+     * @param parameters
+     *            map containing content-type parameters such as
+     *            <code>&quot;boundary&quot;</code>.
+     * @return the newly created <i>Content-Type</i> field.
+     */
+    public static ContentTypeField contentType(String mimeType,
+            Map<String, String> parameters) {
+        if (!isValidMimeType(mimeType))
+            throw new IllegalArgumentException();
+
+        if (parameters == null || parameters.isEmpty()) {
+            return parse(ContentTypeField.PARSER, FieldName.CONTENT_TYPE,
+                    mimeType);
+        } else {
+            StringBuilder sb = new StringBuilder(mimeType);
+            for (Map.Entry<String, String> entry : parameters.entrySet()) {
+                sb.append("; ");
+                sb.append(EncoderUtil.encodeHeaderParameter(entry.getKey(),
+                        entry.getValue()));
+            }
+            String contentType = sb.toString();
+            return contentType(contentType);
+        }
+    }
+
+    /**
+     * Creates a <i>Content-Transfer-Encoding</i> field from the specified raw
+     * field value.
+     * 
+     * @param contentTransferEncoding
+     *            an encoding mechanism such as <code>&quot;7-bit&quot;</code>
+     *            or <code>&quot;quoted-printable&quot;</code>.
+     * @return the newly created <i>Content-Transfer-Encoding</i> field.
+     */
+    public static ContentTransferEncodingField contentTransferEncoding(
+            String contentTransferEncoding) {
+        return parse(ContentTransferEncodingField.PARSER,
+                FieldName.CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
+    }
+
+    /**
+     * Creates a <i>Content-Disposition</i> field from the specified raw field
+     * value. The specified string gets folded into a multiple-line
+     * representation if necessary but is otherwise taken as is.
+     * 
+     * @param contentDisposition
+     *            raw content disposition containing a disposition type and
+     *            optional parameters.
+     * @return the newly created <i>Content-Disposition</i> field.
+     */
+    public static ContentDispositionField contentDisposition(
+            String contentDisposition) {
+        return parse(ContentDispositionField.PARSER,
+                FieldName.CONTENT_DISPOSITION, contentDisposition);
+    }
+
+    /**
+     * Creates a <i>Content-Disposition</i> field from the specified
+     * disposition type and parameters.
+     * 
+     * @param dispositionType
+     *            a disposition type (usually <code>&quot;inline&quot;</code>
+     *            or <code>&quot;attachment&quot;</code>).
+     * @param parameters
+     *            map containing disposition parameters such as
+     *            <code>&quot;filename&quot;</code>.
+     * @return the newly created <i>Content-Disposition</i> field.
+     */
+    public static ContentDispositionField contentDisposition(
+            String dispositionType, Map<String, String> parameters) {
+        if (!isValidDispositionType(dispositionType))
+            throw new IllegalArgumentException();
+
+        if (parameters == null || parameters.isEmpty()) {
+            return parse(ContentDispositionField.PARSER,
+                    FieldName.CONTENT_DISPOSITION, dispositionType);
+        } else {
+            StringBuilder sb = new StringBuilder(dispositionType);
+            for (Map.Entry<String, String> entry : parameters.entrySet()) {
+                sb.append("; ");
+                sb.append(EncoderUtil.encodeHeaderParameter(entry.getKey(),
+                        entry.getValue()));
+            }
+            String contentDisposition = sb.toString();
+            return contentDisposition(contentDisposition);
+        }
+    }
+
+    /**
+     * Creates a <i>Content-Disposition</i> field from the specified
+     * disposition type and filename.
+     * 
+     * @param dispositionType
+     *            a disposition type (usually <code>&quot;inline&quot;</code>
+     *            or <code>&quot;attachment&quot;</code>).
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @return the newly created <i>Content-Disposition</i> field.
+     */
+    public static ContentDispositionField contentDisposition(
+            String dispositionType, String filename) {
+        return contentDisposition(dispositionType, filename, -1, null, null,
+                null);
+    }
+
+    /**
+     * Creates a <i>Content-Disposition</i> field from the specified values.
+     * 
+     * @param dispositionType
+     *            a disposition type (usually <code>&quot;inline&quot;</code>
+     *            or <code>&quot;attachment&quot;</code>).
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @param size
+     *            size parameter value or <code>-1</code> if the parameter
+     *            should not be included.
+     * @return the newly created <i>Content-Disposition</i> field.
+     */
+    public static ContentDispositionField contentDisposition(
+            String dispositionType, String filename, long size) {
+        return contentDisposition(dispositionType, filename, size, null, null,
+                null);
+    }
+
+    /**
+     * Creates a <i>Content-Disposition</i> field from the specified values.
+     * 
+     * @param dispositionType
+     *            a disposition type (usually <code>&quot;inline&quot;</code>
+     *            or <code>&quot;attachment&quot;</code>).
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @param size
+     *            size parameter value or <code>-1</code> if the parameter
+     *            should not be included.
+     * @param creationDate
+     *            creation-date parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @param modificationDate
+     *            modification-date parameter value or <code>null</code> if
+     *            the parameter should not be included.
+     * @param readDate
+     *            read-date parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @return the newly created <i>Content-Disposition</i> field.
+     */
+    public static ContentDispositionField contentDisposition(
+            String dispositionType, String filename, long size,
+            Date creationDate, Date modificationDate, Date readDate) {
+        Map<String, String> parameters = new HashMap<String, String>();
+        if (filename != null) {
+            parameters.put(ContentDispositionField.PARAM_FILENAME, filename);
+        }
+        if (size >= 0) {
+            parameters.put(ContentDispositionField.PARAM_SIZE, Long
+                    .toString(size));
+        }
+        if (creationDate != null) {
+            parameters.put(ContentDispositionField.PARAM_CREATION_DATE,
+                    MimeUtil.formatDate(creationDate, null));
+        }
+        if (modificationDate != null) {
+            parameters.put(ContentDispositionField.PARAM_MODIFICATION_DATE,
+                    MimeUtil.formatDate(modificationDate, null));
+        }
+        if (readDate != null) {
+            parameters.put(ContentDispositionField.PARAM_READ_DATE, MimeUtil
+                    .formatDate(readDate, null));
+        }
+        return contentDisposition(dispositionType, parameters);
+    }
+
+    /**
+     * Creates a <i>Date</i> field from the specified <code>Date</code>
+     * value. The default time zone of the host is used to format the date.
+     * 
+     * @param date
+     *            date value for the header field.
+     * @return the newly created <i>Date</i> field.
+     */
+    public static DateTimeField date(Date date) {
+        return date0(FieldName.DATE, date, null);
+    }
+
+    /**
+     * Creates a date field from the specified field name and <code>Date</code>
+     * value. The default time zone of the host is used to format the date.
+     * 
+     * @param fieldName
+     *            a field name such as <code>Date</code> or
+     *            <code>Resent-Date</code>.
+     * @param date
+     *            date value for the header field.
+     * @return the newly created date field.
+     */
+    public static DateTimeField date(String fieldName, Date date) {
+        checkValidFieldName(fieldName);
+        return date0(fieldName, date, null);
+    }
+
+    /**
+     * Creates a date field from the specified field name, <code>Date</code>
+     * and <code>TimeZone</code> values.
+     * 
+     * @param fieldName
+     *            a field name such as <code>Date</code> or
+     *            <code>Resent-Date</code>.
+     * @param date
+     *            date value for the header field.
+     * @param zone
+     *            the time zone to be used for formatting the date.
+     * @return the newly created date field.
+     */
+    public static DateTimeField date(String fieldName, Date date, TimeZone zone) {
+        checkValidFieldName(fieldName);
+        return date0(fieldName, date, zone);
+    }
+
+    /**
+     * Creates a <i>Message-ID</i> field for the specified host name.
+     * 
+     * @param hostname
+     *            host name to be included in the message ID or
+     *            <code>null</code> if no host name should be included.
+     * @return the newly created <i>Message-ID</i> field.
+     */
+    public static Field messageId(String hostname) {
+        String fieldValue = MimeUtil.createUniqueMessageId(hostname);
+        return parse(UnstructuredField.PARSER, FieldName.MESSAGE_ID, fieldValue);
+    }
+
+    /**
+     * Creates a <i>Subject</i> field from the specified string value. The
+     * specified string may contain non-ASCII characters.
+     * 
+     * @param subject
+     *            the subject string.
+     * @return the newly created <i>Subject</i> field.
+     */
+    public static UnstructuredField subject(String subject) {
+        int usedCharacters = FieldName.SUBJECT.length() + 2;
+        String fieldValue = EncoderUtil.encodeIfNecessary(subject,
+                EncoderUtil.Usage.TEXT_TOKEN, usedCharacters);
+
+        return parse(UnstructuredField.PARSER, FieldName.SUBJECT, fieldValue);
+    }
+
+    /**
+     * Creates a <i>Sender</i> field for the specified mailbox address.
+     * 
+     * @param mailbox
+     *            address to be included in the field.
+     * @return the newly created <i>Sender</i> field.
+     */
+    public static MailboxField sender(Mailbox mailbox) {
+        return mailbox0(FieldName.SENDER, mailbox);
+    }
+
+    /**
+     * Creates a <i>From</i> field for the specified mailbox address.
+     * 
+     * @param mailbox
+     *            address to be included in the field.
+     * @return the newly created <i>From</i> field.
+     */
+    public static MailboxListField from(Mailbox mailbox) {
+        return mailboxList0(FieldName.FROM, Collections.singleton(mailbox));
+    }
+
+    /**
+     * Creates a <i>From</i> field for the specified mailbox addresses.
+     * 
+     * @param mailboxes
+     *            addresses to be included in the field.
+     * @return the newly created <i>From</i> field.
+     */
+    public static MailboxListField from(Mailbox... mailboxes) {
+        return mailboxList0(FieldName.FROM, Arrays.asList(mailboxes));
+    }
+
+    /**
+     * Creates a <i>From</i> field for the specified mailbox addresses.
+     * 
+     * @param mailboxes
+     *            addresses to be included in the field.
+     * @return the newly created <i>From</i> field.
+     */
+    public static MailboxListField from(Iterable<Mailbox> mailboxes) {
+        return mailboxList0(FieldName.FROM, mailboxes);
+    }
+
+    /**
+     * Creates a <i>To</i> field for the specified mailbox or group address.
+     * 
+     * @param address
+     *            mailbox or group address to be included in the field.
+     * @return the newly created <i>To</i> field.
+     */
+    public static AddressListField to(Address address) {
+        return addressList0(FieldName.TO, Collections.singleton(address));
+    }
+
+    /**
+     * Creates a <i>To</i> field for the specified mailbox or group addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>To</i> field.
+     */
+    public static AddressListField to(Address... addresses) {
+        return addressList0(FieldName.TO, Arrays.asList(addresses));
+    }
+
+    /**
+     * Creates a <i>To</i> field for the specified mailbox or group addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>To</i> field.
+     */
+    public static AddressListField to(Iterable<Address> addresses) {
+        return addressList0(FieldName.TO, addresses);
+    }
+
+    /**
+     * Creates a <i>Cc</i> field for the specified mailbox or group address.
+     * 
+     * @param address
+     *            mailbox or group address to be included in the field.
+     * @return the newly created <i>Cc</i> field.
+     */
+    public static AddressListField cc(Address address) {
+        return addressList0(FieldName.CC, Collections.singleton(address));
+    }
+
+    /**
+     * Creates a <i>Cc</i> field for the specified mailbox or group addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>Cc</i> field.
+     */
+    public static AddressListField cc(Address... addresses) {
+        return addressList0(FieldName.CC, Arrays.asList(addresses));
+    }
+
+    /**
+     * Creates a <i>Cc</i> field for the specified mailbox or group addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>Cc</i> field.
+     */
+    public static AddressListField cc(Iterable<Address> addresses) {
+        return addressList0(FieldName.CC, addresses);
+    }
+
+    /**
+     * Creates a <i>Bcc</i> field for the specified mailbox or group address.
+     * 
+     * @param address
+     *            mailbox or group address to be included in the field.
+     * @return the newly created <i>Bcc</i> field.
+     */
+    public static AddressListField bcc(Address address) {
+        return addressList0(FieldName.BCC, Collections.singleton(address));
+    }
+
+    /**
+     * Creates a <i>Bcc</i> field for the specified mailbox or group addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>Bcc</i> field.
+     */
+    public static AddressListField bcc(Address... addresses) {
+        return addressList0(FieldName.BCC, Arrays.asList(addresses));
+    }
+
+    /**
+     * Creates a <i>Bcc</i> field for the specified mailbox or group addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>Bcc</i> field.
+     */
+    public static AddressListField bcc(Iterable<Address> addresses) {
+        return addressList0(FieldName.BCC, addresses);
+    }
+
+    /**
+     * Creates a <i>Reply-To</i> field for the specified mailbox or group
+     * address.
+     * 
+     * @param address
+     *            mailbox or group address to be included in the field.
+     * @return the newly created <i>Reply-To</i> field.
+     */
+    public static AddressListField replyTo(Address address) {
+        return addressList0(FieldName.REPLY_TO, Collections.singleton(address));
+    }
+
+    /**
+     * Creates a <i>Reply-To</i> field for the specified mailbox or group
+     * addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>Reply-To</i> field.
+     */
+    public static AddressListField replyTo(Address... addresses) {
+        return addressList0(FieldName.REPLY_TO, Arrays.asList(addresses));
+    }
+
+    /**
+     * Creates a <i>Reply-To</i> field for the specified mailbox or group
+     * addresses.
+     * 
+     * @param addresses
+     *            mailbox or group addresses to be included in the field.
+     * @return the newly created <i>Reply-To</i> field.
+     */
+    public static AddressListField replyTo(Iterable<Address> addresses) {
+        return addressList0(FieldName.REPLY_TO, addresses);
+    }
+
+    /**
+     * Creates a mailbox field from the specified field name and mailbox
+     * address. Valid field names are <code>Sender</code> and
+     * <code>Resent-Sender</code>.
+     * 
+     * @param fieldName
+     *            the name of the mailbox field (<code>Sender</code> or
+     *            <code>Resent-Sender</code>).
+     * @param mailbox
+     *            mailbox address for the field value.
+     * @return the newly created mailbox field.
+     */
+    public static MailboxField mailbox(String fieldName, Mailbox mailbox) {
+        checkValidFieldName(fieldName);
+        return mailbox0(fieldName, mailbox);
+    }
+
+    /**
+     * Creates a mailbox-list field from the specified field name and mailbox
+     * addresses. Valid field names are <code>From</code> and
+     * <code>Resent-From</code>.
+     * 
+     * @param fieldName
+     *            the name of the mailbox field (<code>From</code> or
+     *            <code>Resent-From</code>).
+     * @param mailboxes
+     *            mailbox addresses for the field value.
+     * @return the newly created mailbox-list field.
+     */
+    public static MailboxListField mailboxList(String fieldName,
+            Iterable<Mailbox> mailboxes) {
+        checkValidFieldName(fieldName);
+        return mailboxList0(fieldName, mailboxes);
+    }
+
+    /**
+     * Creates an address-list field from the specified field name and mailbox
+     * or group addresses. Valid field names are <code>To</code>,
+     * <code>Cc</code>, <code>Bcc</code>, <code>Reply-To</code>,
+     * <code>Resent-To</code>, <code>Resent-Cc</code> and
+     * <code>Resent-Bcc</code>.
+     * 
+     * @param fieldName
+     *            the name of the mailbox field (<code>To</code>,
+     *            <code>Cc</code>, <code>Bcc</code>, <code>Reply-To</code>,
+     *            <code>Resent-To</code>, <code>Resent-Cc</code> or
+     *            <code>Resent-Bcc</code>).
+     * @param addresses
+     *            mailbox or group addresses for the field value.
+     * @return the newly created address-list field.
+     */
+    public static AddressListField addressList(String fieldName,
+            Iterable<Address> addresses) {
+        checkValidFieldName(fieldName);
+        return addressList0(fieldName, addresses);
+    }
+
+    private static DateTimeField date0(String fieldName, Date date,
+            TimeZone zone) {
+        final String formattedDate = MimeUtil.formatDate(date, zone);
+        return parse(DateTimeField.PARSER, fieldName, formattedDate);
+    }
+
+    private static MailboxField mailbox0(String fieldName, Mailbox mailbox) {
+        String fieldValue = encodeAddresses(Collections.singleton(mailbox));
+        return parse(MailboxField.PARSER, fieldName, fieldValue);
+    }
+
+    private static MailboxListField mailboxList0(String fieldName,
+            Iterable<Mailbox> mailboxes) {
+        String fieldValue = encodeAddresses(mailboxes);
+        return parse(MailboxListField.PARSER, fieldName, fieldValue);
+    }
+
+    private static AddressListField addressList0(String fieldName,
+            Iterable<Address> addresses) {
+        String fieldValue = encodeAddresses(addresses);
+        return parse(AddressListField.PARSER, fieldName, fieldValue);
+    }
+
+    private static void checkValidFieldName(String fieldName) {
+        if (!FIELD_NAME_PATTERN.matcher(fieldName).matches())
+            throw new IllegalArgumentException("Invalid field name");
+    }
+
+    private static boolean isValidMimeType(String mimeType) {
+        if (mimeType == null)
+            return false;
+
+        int idx = mimeType.indexOf('/');
+        if (idx == -1)
+            return false;
+
+        String type = mimeType.substring(0, idx);
+        String subType = mimeType.substring(idx + 1);
+        return EncoderUtil.isToken(type) && EncoderUtil.isToken(subType);
+    }
+
+    private static boolean isValidDispositionType(String dispositionType) {
+        if (dispositionType == null)
+            return false;
+
+        return EncoderUtil.isToken(dispositionType);
+    }
+
+    private static <F extends Field> F parse(FieldParser parser,
+            String fieldName, String fieldBody) {
+        String rawStr = MimeUtil.fold(fieldName + ": " + fieldBody, 0);
+        ByteSequence raw = ContentUtil.encode(rawStr);
+
+        Field field = parser.parse(fieldName, fieldBody, raw);
+
+        @SuppressWarnings("unchecked")
+        F f = (F) field;
+        return f;
+    }
+
+    private static String encodeAddresses(Iterable<? extends Address> addresses) {
+        StringBuilder sb = new StringBuilder();
+
+        for (Address address : addresses) {
+            if (sb.length() > 0) {
+                sb.append(", ");
+            }
+            sb.append(address.getEncodedString());
+        }
+
+        return sb.toString();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/MailboxField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/MailboxField.java
new file mode 100644
index 0000000..8ad38eb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/MailboxField.java
@@ -0,0 +1,84 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.field.address.AddressList;

+import org.apache.james.mime4j.field.address.Mailbox;

+import org.apache.james.mime4j.field.address.MailboxList;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Mailbox field such as <code>Sender</code> or <code>Resent-Sender</code>.

+ */

+public class MailboxField extends AbstractField {

+    private static Log log = LogFactory.getLog(MailboxField.class);

+

+    private boolean parsed = false;

+

+    private Mailbox mailbox;

+    private ParseException parseException;

+

+    MailboxField(final String name, final String body, final ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    public Mailbox getMailbox() {

+        if (!parsed)

+            parse();

+

+        return mailbox;

+    }

+

+    @Override

+    public ParseException getParseException() {

+        if (!parsed)

+            parse();

+

+        return parseException;

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        try {

+            MailboxList mailboxList = AddressList.parse(body).flatten();

+            if (mailboxList.size() > 0) {

+                mailbox = mailboxList.get(0);

+            }

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = e;

+        }

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new MailboxField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/MailboxListField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/MailboxListField.java
new file mode 100644
index 0000000..2311ec3
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/MailboxListField.java
@@ -0,0 +1,80 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+import org.apache.james.mime4j.field.address.AddressList;

+import org.apache.james.mime4j.field.address.MailboxList;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Mailbox-list field such as <code>From</code> or <code>Resent-From</code>.

+ */

+public class MailboxListField extends AbstractField {

+    private static Log log = LogFactory.getLog(MailboxListField.class);

+

+    private boolean parsed = false;

+

+    private MailboxList mailboxList;

+    private ParseException parseException;

+

+    MailboxListField(final String name, final String body, final ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    public MailboxList getMailboxList() {

+        if (!parsed)

+            parse();

+

+        return mailboxList;

+    }

+

+    @Override

+    public ParseException getParseException() {

+        if (!parsed)

+            parse();

+

+        return parseException;

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        try {

+            mailboxList = AddressList.parse(body).flatten();

+        } catch (ParseException e) {

+            if (log.isDebugEnabled()) {

+                log.debug("Parsing value '" + body + "': " + e.getMessage());

+            }

+            parseException = e;

+        }

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new MailboxListField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ParseException.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ParseException.java
new file mode 100644
index 0000000..0d815dd
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ParseException.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+import org.apache.james.mime4j.MimeException;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ */
+public class ParseException extends MimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new parse exception with the specified detail message.
+     * 
+     * @param message
+     *            detail message
+     */
+    protected ParseException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new parse exception with the specified cause.
+     * 
+     * @param cause
+     *            the cause
+     */
+    protected ParseException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new parse exception with the specified detail message and
+     * cause.
+     * 
+     * @param message
+     *            detail message
+     * @param cause
+     *            the cause
+     */
+    protected ParseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ParsedField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ParsedField.java
new file mode 100644
index 0000000..4881571
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/ParsedField.java
@@ -0,0 +1,46 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+import org.apache.james.mime4j.parser.Field;
+
+public interface ParsedField extends Field {
+
+    /**
+     * Returns <code>true</code> if this field is valid, i.e. no errors were
+     * encountered while parsing the field value.
+     * 
+     * @return <code>true</code> if this field is valid, <code>false</code>
+     *         otherwise.
+     * @see #getParseException()
+     */
+    boolean isValidField();
+
+    /**
+     * Returns the exception that was thrown by the field parser while parsing
+     * the field value. The result is <code>null</code> if the field is valid
+     * and no errors were encountered.
+     * 
+     * @return the exception that was thrown by the field parser or
+     *         <code>null</code> if the field is valid.
+     */
+    ParseException getParseException();
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/UnstructuredField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/UnstructuredField.java
new file mode 100644
index 0000000..40148ff
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/UnstructuredField.java
@@ -0,0 +1,58 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.codec.DecoderUtil;

+import org.apache.james.mime4j.util.ByteSequence;

+

+/**

+ * Simple unstructured field such as <code>Subject</code>.

+ */

+public class UnstructuredField extends AbstractField {

+    private boolean parsed = false;

+

+    private String value;

+

+    UnstructuredField(String name, String body, ByteSequence raw) {

+        super(name, body, raw);

+    }

+

+    public String getValue() {

+        if (!parsed)

+            parse();

+

+        return value;

+    }

+

+    private void parse() {

+        String body = getBody();

+

+        value = DecoderUtil.decodeEncodedWords(body);

+

+        parsed = true;

+    }

+

+    static final FieldParser PARSER = new FieldParser() {

+        public ParsedField parse(final String name, final String body,

+                final ByteSequence raw) {

+            return new UnstructuredField(name, body, raw);

+        }

+    };

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Address.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Address.java
new file mode 100644
index 0000000..63aa3cc
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Address.java
@@ -0,0 +1,122 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import java.io.Serializable;

+import java.io.StringReader;

+import java.util.List;

+

+import org.apache.james.mime4j.field.address.parser.AddressListParser;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+

+/**

+ * The abstract base for classes that represent RFC2822 addresses. This includes

+ * groups and mailboxes.

+ */

+public abstract class Address implements Serializable {

+

+    private static final long serialVersionUID = 634090661990433426L;

+

+    /**

+     * Adds any mailboxes represented by this address into the given List. Note

+     * that this method has default (package) access, so a doAddMailboxesTo

+     * method is needed to allow the behavior to be overridden by subclasses.

+     */

+    final void addMailboxesTo(List<Mailbox> results) {

+        doAddMailboxesTo(results);

+    }

+

+    /**

+     * Adds any mailboxes represented by this address into the given List. Must

+     * be overridden by concrete subclasses.

+     */

+    protected abstract void doAddMailboxesTo(List<Mailbox> results);

+

+    /**

+     * Formats the address as a human readable string, not including the route.

+     * The resulting string is intended for display purposes only and cannot be

+     * used for transport purposes.

+     * 

+     * @return a string representation of this address intended to be displayed

+     * @see #getDisplayString(boolean)

+     */

+    public final String getDisplayString() {

+        return getDisplayString(false);

+    }

+

+    /**

+     * Formats the address as a human readable string, not including the route.

+     * The resulting string is intended for display purposes only and cannot be

+     * used for transport purposes.

+     * 

+     * For example, if the unparsed address was

+     * 

+     * <"Joe Cheng"@joecheng.com>

+     * 

+     * this method would return

+     * 

+     * <Joe Cheng@joecheng.com>

+     * 

+     * which is not valid for transport; the local part would need to be

+     * re-quoted.

+     * 

+     * @param includeRoute

+     *            <code>true</code> if the route should be included if it

+     *            exists, <code>false</code> otherwise.

+     * @return a string representation of this address intended to be displayed.

+     */

+    public abstract String getDisplayString(boolean includeRoute);

+

+    /**

+     * Returns a string representation of this address that can be used for

+     * transport purposes. The route is never included in this representation

+     * because routes are obsolete and RFC 5322 states that obsolete syntactic

+     * forms MUST NOT be generated.

+     * 

+     * @return a string representation of this address intended for transport

+     *         purposes.

+     */

+    public abstract String getEncodedString();

+

+    /**

+     * Parses the specified raw string into an address.

+     * 

+     * @param rawAddressString

+     *            string to parse.

+     * @return an <code>Address</code> object for the specified string.

+     * @throws IllegalArgumentException

+     *             if the raw string does not represent a single address.

+     */

+    public static Address parse(String rawAddressString) {

+        AddressListParser parser = new AddressListParser(new StringReader(

+                rawAddressString));

+        try {

+            return Builder.getInstance().buildAddress(parser.parseAddress());

+        } catch (ParseException e) {

+            throw new IllegalArgumentException(e);

+        }

+    }

+

+    @Override

+    public String toString() {

+        return getDisplayString(false);

+    }

+

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/AddressList.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/AddressList.java
new file mode 100644
index 0000000..0eaba3b
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/AddressList.java
@@ -0,0 +1,148 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import org.apache.james.mime4j.field.address.parser.AddressListParser;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+

+import java.io.Serializable;

+import java.io.StringReader;

+import java.util.AbstractList;

+import java.util.ArrayList;

+import java.util.Collections;

+import java.util.List;

+

+/**

+ * An immutable, random-access list of Address objects.

+ */

+public class AddressList extends AbstractList<Address> implements Serializable {

+

+    private static final long serialVersionUID = 1L;

+

+    private final List<? extends Address> addresses;

+

+    /**

+     * @param addresses

+     *            A List that contains only Address objects.

+     * @param dontCopy

+     *            true iff it is not possible for the addresses list to be

+     *            modified by someone else.

+     */

+    public AddressList(List<? extends Address> addresses, boolean dontCopy) {

+        if (addresses != null)

+            this.addresses = dontCopy ? addresses : new ArrayList<Address>(

+                    addresses);

+        else

+            this.addresses = Collections.emptyList();

+    }

+

+    /**

+     * The number of elements in this list.

+     */

+    @Override

+    public int size() {

+        return addresses.size();

+    }

+

+    /**

+     * Gets an address.

+     */

+    @Override

+    public Address get(int index) {

+        return addresses.get(index);

+    }

+

+    /**

+     * Returns a flat list of all mailboxes represented in this address list.

+     * Use this if you don't care about grouping.

+     */

+    public MailboxList flatten() {

+        // in the common case, all addresses are mailboxes

+        boolean groupDetected = false;

+        for (Address addr : addresses) {

+            if (!(addr instanceof Mailbox)) {

+                groupDetected = true;

+                break;

+            }

+        }

+

+        if (!groupDetected) {

+            @SuppressWarnings("unchecked")

+            final List<Mailbox> mailboxes = (List<Mailbox>) addresses;

+            return new MailboxList(mailboxes, true);

+        }

+

+        List<Mailbox> results = new ArrayList<Mailbox>();

+        for (Address addr : addresses) {

+            addr.addMailboxesTo(results);

+        }

+

+        // copy-on-construct this time, because subclasses

+        // could have held onto a reference to the results

+        return new MailboxList(results, false);

+    }

+

+    /**

+     * Dumps a representation of this address list to stdout, for debugging

+     * purposes.

+     */

+    public void print() {

+        for (Address addr : addresses) {

+            System.out.println(addr.toString());

+        }

+    }

+

+    /**

+     * Parse the address list string, such as the value of a From, To, Cc, Bcc,

+     * Sender, or Reply-To header.

+     * 

+     * The string MUST be unfolded already.

+     */

+    public static AddressList parse(String rawAddressList)

+            throws ParseException {

+        AddressListParser parser = new AddressListParser(new StringReader(

+                rawAddressList));

+        return Builder.getInstance().buildAddressList(parser.parseAddressList());

+    }

+

+    /**

+     * Test console.

+     */

+    public static void main(String[] args) throws Exception {

+        java.io.BufferedReader reader = new java.io.BufferedReader(

+                new java.io.InputStreamReader(System.in));

+        while (true) {

+            try {

+                System.out.print("> ");

+                String line = reader.readLine();

+                if (line.length() == 0 || line.toLowerCase().equals("exit")

+                        || line.toLowerCase().equals("quit")) {

+                    System.out.println("Goodbye.");

+                    return;

+                }

+                AddressList list = parse(line);

+                list.print();

+            } catch (Exception e) {

+                e.printStackTrace();

+                Thread.sleep(300);

+            }

+        }

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Builder.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Builder.java
new file mode 100644
index 0000000..efc4071
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Builder.java
@@ -0,0 +1,224 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import org.apache.james.mime4j.codec.DecoderUtil;

+import org.apache.james.mime4j.field.address.parser.ASTaddr_spec;

+import org.apache.james.mime4j.field.address.parser.ASTaddress;

+import org.apache.james.mime4j.field.address.parser.ASTaddress_list;

+import org.apache.james.mime4j.field.address.parser.ASTangle_addr;

+import org.apache.james.mime4j.field.address.parser.ASTdomain;

+import org.apache.james.mime4j.field.address.parser.ASTgroup_body;

+import org.apache.james.mime4j.field.address.parser.ASTlocal_part;

+import org.apache.james.mime4j.field.address.parser.ASTmailbox;

+import org.apache.james.mime4j.field.address.parser.ASTname_addr;

+import org.apache.james.mime4j.field.address.parser.ASTphrase;

+import org.apache.james.mime4j.field.address.parser.ASTroute;

+import org.apache.james.mime4j.field.address.parser.Node;

+import org.apache.james.mime4j.field.address.parser.SimpleNode;

+import org.apache.james.mime4j.field.address.parser.Token;

+

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+

+/**

+ * Transforms the JJTree-generated abstract syntax tree into a graph of

+ * org.apache.james.mime4j.field.address objects.

+ */

+class Builder {

+

+    private static Builder singleton = new Builder();

+

+    public static Builder getInstance() {

+        return singleton;

+    }

+

+    public AddressList buildAddressList(ASTaddress_list node) {

+        List<Address> list = new ArrayList<Address>();

+        for (int i = 0; i < node.jjtGetNumChildren(); i++) {

+            ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);

+            Address address = buildAddress(childNode);

+            list.add(address);

+        }

+        return new AddressList(list, true);

+    }

+

+    public Address buildAddress(ASTaddress node) {

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        Node n = it.next();

+        if (n instanceof ASTaddr_spec) {

+            return buildAddrSpec((ASTaddr_spec) n);

+        } else if (n instanceof ASTangle_addr) {

+            return buildAngleAddr((ASTangle_addr) n);

+        } else if (n instanceof ASTphrase) {

+            String name = buildString((ASTphrase) n, false);

+            Node n2 = it.next();

+            if (n2 instanceof ASTgroup_body) {

+                return new Group(name, buildGroupBody((ASTgroup_body) n2));

+            } else if (n2 instanceof ASTangle_addr) {

+                name = DecoderUtil.decodeEncodedWords(name);

+                return new Mailbox(name, buildAngleAddr((ASTangle_addr) n2));

+            } else {

+                throw new IllegalStateException();

+            }

+        } else {

+            throw new IllegalStateException();

+        }

+    }

+

+    private MailboxList buildGroupBody(ASTgroup_body node) {

+        List<Mailbox> results = new ArrayList<Mailbox>();

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        while (it.hasNext()) {

+            Node n = it.next();

+            if (n instanceof ASTmailbox)

+                results.add(buildMailbox((ASTmailbox) n));

+            else

+                throw new IllegalStateException();

+        }

+        return new MailboxList(results, true);

+    }

+

+    public Mailbox buildMailbox(ASTmailbox node) {

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        Node n = it.next();

+        if (n instanceof ASTaddr_spec) {

+            return buildAddrSpec((ASTaddr_spec) n);

+        } else if (n instanceof ASTangle_addr) {

+            return buildAngleAddr((ASTangle_addr) n);

+        } else if (n instanceof ASTname_addr) {

+            return buildNameAddr((ASTname_addr) n);

+        } else {

+            throw new IllegalStateException();

+        }

+    }

+

+    private Mailbox buildNameAddr(ASTname_addr node) {

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        Node n = it.next();

+        String name;

+        if (n instanceof ASTphrase) {

+            name = buildString((ASTphrase) n, false);

+        } else {

+            throw new IllegalStateException();

+        }

+

+        n = it.next();

+        if (n instanceof ASTangle_addr) {

+            name = DecoderUtil.decodeEncodedWords(name);

+            return new Mailbox(name, buildAngleAddr((ASTangle_addr) n));

+        } else {

+            throw new IllegalStateException();

+        }

+    }

+

+    private Mailbox buildAngleAddr(ASTangle_addr node) {

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        DomainList route = null;

+        Node n = it.next();

+        if (n instanceof ASTroute) {

+            route = buildRoute((ASTroute) n);

+            n = it.next();

+        } else if (n instanceof ASTaddr_spec) {

+            // do nothing

+        }

+        else

+            throw new IllegalStateException();

+

+        if (n instanceof ASTaddr_spec)

+            return buildAddrSpec(route, (ASTaddr_spec) n);

+        else

+            throw new IllegalStateException();

+    }

+

+    private DomainList buildRoute(ASTroute node) {

+        List<String> results = new ArrayList<String>(node.jjtGetNumChildren());

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        while (it.hasNext()) {

+            Node n = it.next();

+            if (n instanceof ASTdomain)

+                results.add(buildString((ASTdomain) n, true));

+            else

+                throw new IllegalStateException();

+        }

+        return new DomainList(results, true);

+    }

+

+    private Mailbox buildAddrSpec(ASTaddr_spec node) {

+        return buildAddrSpec(null, node);

+    }

+

+    private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {

+        ChildNodeIterator it = new ChildNodeIterator(node);

+        String localPart = buildString((ASTlocal_part) it.next(), true);

+        String domain = buildString((ASTdomain) it.next(), true);

+        return new Mailbox(route, localPart, domain);

+    }

+

+    private String buildString(SimpleNode node, boolean stripSpaces) {

+        Token head = node.firstToken;

+        Token tail = node.lastToken;

+        StringBuilder out = new StringBuilder();

+

+        while (head != tail) {

+            out.append(head.image);

+            head = head.next;

+            if (!stripSpaces)

+                addSpecials(out, head.specialToken);

+        }

+        out.append(tail.image);

+

+        return out.toString();

+    }

+

+    private void addSpecials(StringBuilder out, Token specialToken) {

+        if (specialToken != null) {

+            addSpecials(out, specialToken.specialToken);

+            out.append(specialToken.image);

+        }

+    }

+

+    private static class ChildNodeIterator implements Iterator<Node> {

+

+        private SimpleNode simpleNode;

+        private int index;

+        private int len;

+

+        public ChildNodeIterator(SimpleNode simpleNode) {

+            this.simpleNode = simpleNode;

+            this.len = simpleNode.jjtGetNumChildren();

+            this.index = 0;

+        }

+

+        public void remove() {

+            throw new UnsupportedOperationException();

+        }

+

+        public boolean hasNext() {

+            return index < len;

+        }

+

+        public Node next() {

+            return simpleNode.jjtGetChild(index++);

+        }

+

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/DomainList.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/DomainList.java
new file mode 100644
index 0000000..b15d71f
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/DomainList.java
@@ -0,0 +1,95 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import java.io.Serializable;

+import java.util.AbstractList;

+import java.util.ArrayList;

+import java.util.Collections;

+import java.util.List;

+

+/**

+ * An immutable, random-access list of Strings (that are supposedly domain names

+ * or domain literals).

+ */

+public class DomainList extends AbstractList<String> implements Serializable {

+

+    private static final long serialVersionUID = 1L;

+

+    private final List<String> domains;

+

+    /**

+     * @param domains

+     *            A List that contains only String objects.

+     * @param dontCopy

+     *            true iff it is not possible for the domains list to be

+     *            modified by someone else.

+     */

+    public DomainList(List<String> domains, boolean dontCopy) {

+        if (domains != null)

+            this.domains = dontCopy ? domains : new ArrayList<String>(domains);

+        else

+            this.domains = Collections.emptyList();

+    }

+

+    /**

+     * The number of elements in this list.

+     */

+    @Override

+    public int size() {

+        return domains.size();

+    }

+

+    /**

+     * Gets the domain name or domain literal at the specified index.

+     * 

+     * @throws IndexOutOfBoundsException

+     *             If index is &lt; 0 or &gt;= size().

+     */

+    @Override

+    public String get(int index) {

+        return domains.get(index);

+    }

+

+    /**

+     * Returns the list of domains formatted as a route string (not including

+     * the trailing ':').

+     */

+    public String toRouteString() {

+        StringBuilder sb = new StringBuilder();

+

+        for (String domain : domains) {

+            if (sb.length() > 0) {

+                sb.append(',');

+            }

+

+            sb.append("@");

+            sb.append(domain);

+        }

+

+        return sb.toString();

+    }

+

+    @Override

+    public String toString() {

+        return toRouteString();

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Group.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Group.java
new file mode 100644
index 0000000..32b6afc
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Group.java
@@ -0,0 +1,161 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Collection;

+import java.util.List;

+

+import org.apache.james.mime4j.codec.EncoderUtil;

+

+/**

+ * A named group of zero or more mailboxes.

+ */

+public class Group extends Address {

+

+    private static final long serialVersionUID = 1L;

+

+    private final String name;

+    private final MailboxList mailboxList;

+

+    /**

+     * @param name

+     *            The group name.

+     * @param mailboxes

+     *            The mailboxes in this group.

+     */

+    public Group(String name, Mailbox... mailboxes) {

+        this(name, new MailboxList(Arrays.asList(mailboxes), true));

+    }

+

+    /**

+     * @param name

+     *            The group name.

+     * @param mailboxes

+     *            The mailboxes in this group.

+     */

+    public Group(String name, Collection<Mailbox> mailboxes) {

+        this(name, new MailboxList(new ArrayList<Mailbox>(mailboxes), true));

+    }

+

+    /**

+     * @param name

+     *            The group name.

+     * @param mailboxes

+     *            The mailboxes in this group.

+     */

+    public Group(String name, MailboxList mailboxes) {

+        if (name == null)

+            throw new IllegalArgumentException();

+        if (mailboxes == null)

+            throw new IllegalArgumentException();

+

+        this.name = name;

+        this.mailboxList = mailboxes;

+    }

+

+    /**

+     * Parses the specified raw string into a group address.

+     * 

+     * @param rawGroupString

+     *            string to parse.

+     * @return a <code>Group</code> object for the specified string.

+     * @throws IllegalArgumentException

+     *             if the raw string does not represent a single group address.

+     */

+    public static Group parse(String rawGroupString) {

+        Address address = Address.parse(rawGroupString);

+        if (!(address instanceof Group))

+            throw new IllegalArgumentException("Not a group address");

+

+        return (Group) address;

+    }

+

+    /**

+     * Returns the group name.

+     */

+    public String getName() {

+        return name;

+    }

+

+    /**

+     * Returns the mailboxes in this group.

+     */

+    public MailboxList getMailboxes() {

+        return mailboxList;

+    }

+

+    @Override

+    public String getDisplayString(boolean includeRoute) {

+        StringBuilder sb = new StringBuilder();

+

+        sb.append(name);

+        sb.append(':');

+

+        boolean first = true;

+        for (Mailbox mailbox : mailboxList) {

+            if (first) {

+                first = false;

+            } else {

+                sb.append(',');

+            }

+

+            sb.append(' ');

+            sb.append(mailbox.getDisplayString(includeRoute));

+        }

+

+        sb.append(";");

+

+        return sb.toString();

+    }

+

+    @Override

+    public String getEncodedString() {

+        StringBuilder sb = new StringBuilder();

+

+        sb.append(EncoderUtil.encodeAddressDisplayName(name));

+        sb.append(':');

+

+        boolean first = true;

+        for (Mailbox mailbox : mailboxList) {

+            if (first) {

+                first = false;

+            } else {

+                sb.append(',');

+            }

+

+            sb.append(' ');

+            sb.append(mailbox.getEncodedString());

+        }

+

+        sb.append(';');

+

+        return sb.toString();

+    }

+

+    @Override

+    protected void doAddMailboxesTo(List<Mailbox> results) {

+        for (Mailbox mailbox : mailboxList) {

+            results.add(mailbox);

+        }

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Mailbox.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Mailbox.java
new file mode 100644
index 0000000..63459cc
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/Mailbox.java
@@ -0,0 +1,288 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import java.io.StringReader;

+import java.util.Collections;

+import java.util.List;

+import java.util.Locale;

+

+import org.apache.james.mime4j.codec.EncoderUtil;

+import org.apache.james.mime4j.field.address.parser.AddressListParser;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+

+/**

+ * Represents a single e-mail address.

+ */

+public class Mailbox extends Address {

+

+    private static final long serialVersionUID = 1L;

+

+    private static final DomainList EMPTY_ROUTE_LIST = new DomainList(

+            Collections.<String> emptyList(), true);

+

+    private final String name;

+    private final DomainList route;

+    private final String localPart;

+    private final String domain;

+

+    /**

+     * Creates an unnamed mailbox without a route. Routes are obsolete.

+     * 

+     * @param localPart

+     *            The part of the e-mail address to the left of the "@".

+     * @param domain

+     *            The part of the e-mail address to the right of the "@".

+     */

+    public Mailbox(String localPart, String domain) {

+        this(null, null, localPart, domain);

+    }

+

+    /**

+     * Creates an unnamed mailbox with a route. Routes are obsolete.

+     * 

+     * @param route

+     *            The zero or more domains that make up the route. May be

+     *            <code>null</code>.

+     * @param localPart

+     *            The part of the e-mail address to the left of the "@".

+     * @param domain

+     *            The part of the e-mail address to the right of the "@".

+     */

+    public Mailbox(DomainList route, String localPart, String domain) {

+        this(null, route, localPart, domain);

+    }

+

+    /**

+     * Creates a named mailbox without a route. Routes are obsolete.

+     * 

+     * @param name

+     *            the name of the e-mail address. May be <code>null</code>.

+     * @param localPart

+     *            The part of the e-mail address to the left of the "@".

+     * @param domain

+     *            The part of the e-mail address to the right of the "@".

+     */

+    public Mailbox(String name, String localPart, String domain) {

+        this(name, null, localPart, domain);

+    }

+

+    /**

+     * Creates a named mailbox with a route. Routes are obsolete.

+     * 

+     * @param name

+     *            the name of the e-mail address. May be <code>null</code>.

+     * @param route

+     *            The zero or more domains that make up the route. May be

+     *            <code>null</code>.

+     * @param localPart

+     *            The part of the e-mail address to the left of the "@".

+     * @param domain

+     *            The part of the e-mail address to the right of the "@".

+     */

+    public Mailbox(String name, DomainList route, String localPart,

+            String domain) {

+        if (localPart == null || localPart.length() == 0)

+            throw new IllegalArgumentException();

+

+        this.name = name == null || name.length() == 0 ? null : name;

+        this.route = route == null ? EMPTY_ROUTE_LIST : route;

+        this.localPart = localPart;

+        this.domain = domain == null || domain.length() == 0 ? null : domain;

+    }

+

+    /**

+     * Creates a named mailbox based on an unnamed mailbox. Package private;

+     * internally used by Builder.

+     */

+    Mailbox(String name, Mailbox baseMailbox) {

+        this(name, baseMailbox.getRoute(), baseMailbox.getLocalPart(),

+                baseMailbox.getDomain());

+    }

+

+    /**

+     * Parses the specified raw string into a mailbox address.

+     * 

+     * @param rawMailboxString

+     *            string to parse.

+     * @return a <code>Mailbox</code> object for the specified string.

+     * @throws IllegalArgumentException

+     *             if the raw string does not represent a single mailbox

+     *             address.

+     */

+    public static Mailbox parse(String rawMailboxString) {

+        AddressListParser parser = new AddressListParser(new StringReader(

+                rawMailboxString));

+        try {

+            return Builder.getInstance().buildMailbox(parser.parseMailbox());

+        } catch (ParseException e) {

+            throw new IllegalArgumentException(e);

+        }

+    }

+

+    /**

+     * Returns the name of the mailbox or <code>null</code> if it does not

+     * have a name.

+     */

+    public String getName() {

+        return name;

+    }

+

+    /**

+     * Returns the route list. If the mailbox does not have a route an empty

+     * domain list is returned.

+     */

+    public DomainList getRoute() {

+        return route;

+    }

+

+    /**

+     * Returns the left part of the e-mail address (before "@").

+     */

+    public String getLocalPart() {

+        return localPart;

+    }

+

+    /**

+     * Returns the right part of the e-mail address (after "@").

+     */

+    public String getDomain() {

+        return domain;

+    }

+

+    /**

+     * Returns the address in the form <i>localPart@domain</i>.

+     * 

+     * @return the address part of this mailbox.

+     */

+    public String getAddress() {

+        if (domain == null) {

+            return localPart;

+        } else {

+            return localPart + '@' + domain;

+        }

+    }

+

+    @Override

+    public String getDisplayString(boolean includeRoute) {

+        includeRoute &= route != null;

+        boolean includeAngleBrackets = name != null || includeRoute;

+

+        StringBuilder sb = new StringBuilder();

+

+        if (name != null) {

+            sb.append(name);

+            sb.append(' ');

+        }

+

+        if (includeAngleBrackets) {

+            sb.append('<');

+        }

+

+        if (includeRoute) {

+            sb.append(route.toRouteString());

+            sb.append(':');

+        }

+

+        sb.append(localPart);

+

+        if (domain != null) {

+            sb.append('@');

+            sb.append(domain);

+        }

+

+        if (includeAngleBrackets) {

+            sb.append('>');

+        }

+

+        return sb.toString();

+    }

+

+    @Override

+    public String getEncodedString() {

+        StringBuilder sb = new StringBuilder();

+

+        if (name != null) {

+            sb.append(EncoderUtil.encodeAddressDisplayName(name));

+            sb.append(" <");

+        }

+

+        sb.append(EncoderUtil.encodeAddressLocalPart(localPart));

+

+        // domain = dot-atom / domain-literal

+        // domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]

+        // dtext = %d33-90 / %d94-126

+        if (domain != null) {

+            sb.append('@');

+            sb.append(domain);

+        }

+

+        if (name != null) {

+            sb.append('>');

+        }

+

+        return sb.toString();

+    }

+

+    @Override

+    public int hashCode() {

+        return getCanonicalizedAddress().hashCode();

+    }

+

+    /**

+     * Indicates whether some other object is "equal to" this mailbox.

+     * <p>

+     * An object is considered to be equal to this mailbox if it is an instance

+     * of class <code>Mailbox</code> that holds the same address as this one.

+     * The domain is considered to be case-insensitive but the local-part is not

+     * (because of RFC 5321: <cite>the local-part of a mailbox MUST BE treated

+     * as case sensitive</cite>).

+     * 

+     * @param obj

+     *            the object to test for equality.

+     * @return <code>true</code> if the specified object is a

+     *         <code>Mailbox</code> that holds the same address as this one.

+     */

+    @Override

+    public boolean equals(Object obj) {

+        if (obj == this)

+            return true;

+        if (!(obj instanceof Mailbox))

+            return false;

+

+        Mailbox other = (Mailbox) obj;

+        return getCanonicalizedAddress()

+                .equals(other.getCanonicalizedAddress());

+    }

+

+    @Override

+    protected final void doAddMailboxesTo(List<Mailbox> results) {

+        results.add(this);

+    }

+

+    private Object getCanonicalizedAddress() {

+        if (domain == null) {

+            return localPart;

+        } else {

+            return localPart + '@' + domain.toLowerCase(Locale.US);

+        }

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/MailboxList.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/MailboxList.java
new file mode 100644
index 0000000..7202354
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/MailboxList.java
@@ -0,0 +1,79 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import java.io.Serializable;

+import java.util.AbstractList;

+import java.util.ArrayList;

+import java.util.Collections;

+import java.util.List;

+

+/**

+ * An immutable, random-access list of Mailbox objects.

+ */

+public class MailboxList extends AbstractList<Mailbox> implements Serializable {

+

+    private static final long serialVersionUID = 1L;

+

+    private final List<Mailbox> mailboxes;

+

+    /**

+     * @param mailboxes

+     *            A List that contains only Mailbox objects.

+     * @param dontCopy

+     *            true iff it is not possible for the mailboxes list to be

+     *            modified by someone else.

+     */

+    public MailboxList(List<Mailbox> mailboxes, boolean dontCopy) {

+        if (mailboxes != null)

+            this.mailboxes = dontCopy ? mailboxes : new ArrayList<Mailbox>(

+                    mailboxes);

+        else

+            this.mailboxes = Collections.emptyList();

+    }

+

+    /**

+     * The number of elements in this list.

+     */

+    @Override

+    public int size() {

+        return mailboxes.size();

+    }

+

+    /**

+     * Gets an address.

+     */

+    @Override

+    public Mailbox get(int index) {

+        return mailboxes.get(index);

+    }

+

+    /**

+     * Dumps a representation of this mailbox list to stdout, for debugging

+     * purposes.

+     */

+    public void print() {

+        for (int i = 0; i < size(); i++) {

+            Mailbox mailbox = get(i);

+            System.out.println(mailbox.toString());

+        }

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/parser/BaseNode.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/parser/BaseNode.java
new file mode 100644
index 0000000..371bc44
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/address/parser/BaseNode.java
@@ -0,0 +1,28 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address.parser;

+

+

+public abstract class BaseNode implements Node {

+  

+  public Token firstToken;

+  public Token lastToken;

+

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/datetime/DateTime.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/datetime/DateTime.java
new file mode 100644
index 0000000..a1ff74c
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/field/datetime/DateTime.java
@@ -0,0 +1,165 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.datetime;

+

+import java.util.Calendar;

+import java.util.Date;

+import java.util.GregorianCalendar;

+import java.util.TimeZone;

+

+public class DateTime {

+    private final Date date;

+    private final int year;

+    private final int month;

+    private final int day;

+    private final int hour;

+    private final int minute;

+    private final int second;

+    private final int timeZone;

+

+    public DateTime(String yearString, int month, int day, int hour, int minute, int second, int timeZone) {

+        this.year = convertToYear(yearString);

+        this.date = convertToDate(year, month, day, hour, minute, second, timeZone);

+        this.month = month;

+        this.day = day;

+        this.hour = hour;

+        this.minute = minute;

+        this.second = second;

+        this.timeZone = timeZone;

+    }

+

+    private int convertToYear(String yearString) {

+        int year = Integer.parseInt(yearString);

+        switch (yearString.length()) {

+            case 1:

+            case 2:

+                if (year >= 0 && year < 50)

+                    return 2000 + year;

+                else

+                    return 1900 + year;

+            case 3:

+                return 1900 + year;

+            default:

+                return year;

+        }

+    }

+

+    public static Date convertToDate(int year, int month, int day, int hour, int minute, int second, int timeZone) {

+        Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT+0"));

+        c.set(year, month - 1, day, hour, minute, second);

+        c.set(Calendar.MILLISECOND, 0);

+

+        if (timeZone != Integer.MIN_VALUE) {

+            int minutes = ((timeZone / 100) * 60) + timeZone % 100;

+            c.add(Calendar.MINUTE, -1 * minutes);

+        }

+

+        return c.getTime();

+    }

+

+    public Date getDate() {

+        return date;

+    }

+

+    public int getYear() {

+        return year;

+    }

+

+    public int getMonth() {

+        return month;

+    }

+

+    public int getDay() {

+        return day;

+    }

+

+    public int getHour() {

+        return hour;

+    }

+

+    public int getMinute() {

+        return minute;

+    }

+

+    public int getSecond() {

+        return second;

+    }

+

+    public int getTimeZone() {

+        return timeZone;

+    }

+

+    public void print() {

+        System.out.println(toString());

+    }

+

+    @Override

+    public String toString() {

+        return getYear() + " " + getMonth() + " " + getDay() + "; " + getHour() + " " + getMinute() + " " + getSecond() + " " + getTimeZone();

+    }

+

+    @Override

+    public int hashCode() {

+        final int PRIME = 31;

+        int result = 1;

+        result = PRIME * result + ((date == null) ? 0 : date.hashCode());

+        result = PRIME * result + day;

+        result = PRIME * result + hour;

+        result = PRIME * result + minute;

+        result = PRIME * result + month;

+        result = PRIME * result + second;

+        result = PRIME * result + timeZone;

+        result = PRIME * result + year;

+        return result;

+    }

+

+    @Override

+    public boolean equals(Object obj) {

+        if (this == obj)

+            return true;

+        if (obj == null)

+            return false;

+        if (getClass() != obj.getClass())

+            return false;

+        final DateTime other = (DateTime) obj;

+        if (date == null) {

+            if (other.date != null)

+                return false;

+        } else if (!date.equals(other.date))

+            return false;

+        if (day != other.day)

+            return false;

+        if (hour != other.hour)

+            return false;

+        if (minute != other.minute)

+            return false;

+        if (month != other.month)

+            return false;

+        if (second != other.second)

+            return false;

+        if (timeZone != other.timeZone)

+            return false;

+        if (year != other.year)

+            return false;

+        return true;

+    }

+

+    

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/BufferedLineReaderInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/BufferedLineReaderInputStream.java
new file mode 100644
index 0000000..601acaf
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/BufferedLineReaderInputStream.java
@@ -0,0 +1,345 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Input buffer that can be used to search for patterns using Quick Search 
+ * algorithm in data read from an {@link InputStream}. 
+ */
+public class BufferedLineReaderInputStream extends LineReaderInputStream {
+
+    private boolean truncated;
+    
+    private byte[] buffer;
+    
+    private int bufpos;
+    private int buflen;
+    
+    private final int maxLineLen;
+    
+    public BufferedLineReaderInputStream(
+            final InputStream instream, 
+            int buffersize,
+            int maxLineLen) {
+        super(instream);
+        if (instream == null) {
+            throw new IllegalArgumentException("Input stream may not be null");
+        }
+        if (buffersize <= 0) {
+            throw new IllegalArgumentException("Buffer size may not be negative or zero");
+        }
+        this.buffer = new byte[buffersize];
+        this.bufpos = 0;
+        this.buflen = 0;
+        this.maxLineLen = maxLineLen;
+        this.truncated = false;
+    }
+
+    public BufferedLineReaderInputStream(
+            final InputStream instream, 
+            int buffersize) {
+        this(instream, buffersize, -1);
+    }
+
+    private void expand(int newlen) {
+        byte newbuffer[] = new byte[newlen];
+        int len = this.buflen - this.bufpos;
+        if (len > 0) {
+            System.arraycopy(this.buffer, this.bufpos, newbuffer, this.bufpos, len);
+        }
+        this.buffer = newbuffer;
+    }
+    
+    public void ensureCapacity(int len) {
+        if (len > this.buffer.length) {
+            expand(len);
+        }
+    }
+    
+    public int fillBuffer() throws IOException {
+        // compact the buffer if necessary
+        if (this.bufpos > 0) {
+            int len = this.buflen - this.bufpos;
+            if (len > 0) {
+                System.arraycopy(this.buffer, this.bufpos, this.buffer, 0, len);
+            }
+            this.bufpos = 0;
+            this.buflen = len;
+        }
+        int l;
+        int off = this.buflen;
+        int len = this.buffer.length - off;
+        l = in.read(this.buffer, off, len);
+        if (l == -1) {
+            return -1;
+        } else {
+            this.buflen = off + l;
+            return l;
+        }
+    }
+
+    public boolean hasBufferedData() {
+        return this.bufpos < this.buflen;
+    }
+
+    public void truncate() {
+        clear();
+        this.truncated = true;
+    }
+    
+    @Override
+    public int read() throws IOException {
+        if (this.truncated) {
+            return -1;
+        }
+        int noRead = 0;
+        while (!hasBufferedData()) {
+            noRead = fillBuffer();
+            if (noRead == -1) {
+                return -1;
+            }
+        }
+        return this.buffer[this.bufpos++] & 0xff;
+    }
+    
+    @Override
+    public int read(final byte[] b, int off, int len) throws IOException {
+        if (this.truncated) {
+            return -1;
+        }
+        if (b == null) {
+            return 0;
+        }
+        int noRead = 0;
+        while (!hasBufferedData()) {
+            noRead = fillBuffer();
+            if (noRead == -1) {
+                return -1;
+            }
+        }
+        int chunk = this.buflen - this.bufpos;
+        if (chunk > len) {
+            chunk = len;
+        }
+        System.arraycopy(this.buffer, this.bufpos, b, off, chunk);
+        this.bufpos += chunk;
+        return chunk;
+    }
+    
+    @Override
+    public int read(final byte[] b) throws IOException {
+        if (this.truncated) {
+            return -1;
+        }
+        if (b == null) {
+            return 0;
+        }
+        return read(b, 0, b.length);
+    }
+    
+    @Override
+    public boolean markSupported() {
+        return false;
+    }
+
+    
+    @Override
+    public int readLine(final ByteArrayBuffer dst) throws IOException {
+        if (dst == null) {
+            throw new IllegalArgumentException("Buffer may not be null");
+        }
+        if (this.truncated) {
+            return -1;
+        }
+        int total = 0;
+        boolean found = false;
+        int bytesRead = 0;
+        while (!found) {
+            if (!hasBufferedData()) {
+                bytesRead = fillBuffer();
+                if (bytesRead == -1) {
+                    break;
+                }
+            }
+            int i = indexOf((byte)'\n');
+            int chunk;
+            if (i != -1) {
+                found = true;
+                chunk = i + 1 - pos();
+            } else {
+                chunk = length();
+            }
+            if (chunk > 0) {
+                dst.append(buf(), pos(), chunk);
+                skip(chunk);
+                total += chunk;
+            }
+            if (this.maxLineLen > 0 && dst.length() >= this.maxLineLen) {
+                throw new MaxLineLimitException("Maximum line length limit exceeded");
+            }
+        }
+        if (total == 0 && bytesRead == -1) {
+            return -1;
+        } else {
+            return total;
+        }
+    }
+
+    /**
+     * Implements quick search algorithm as published by
+     * <p> 
+     * SUNDAY D.M., 1990, 
+     * A very fast substring search algorithm, 
+     * Communications of the ACM . 33(8):132-142.
+     * </p>
+     */
+    public int indexOf(final byte[] pattern, int off, int len) {
+        if (pattern == null) {
+            throw new IllegalArgumentException("Pattern may not be null");
+        }
+        if (off < this.bufpos || len < 0 || off + len > this.buflen) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (len < pattern.length) {
+            return -1;
+        }
+        
+        int[] shiftTable = new int[256];
+        for (int i = 0; i < shiftTable.length; i++) {
+            shiftTable[i] = pattern.length + 1;
+        }
+        for (int i = 0; i < pattern.length; i++) {
+            int x = pattern[i] & 0xff;
+            shiftTable[x] = pattern.length - i;
+        }
+        
+        int j = 0;
+        while (j <= len - pattern.length) {
+            int cur = off + j;
+            boolean match = true;
+            for (int i = 0; i < pattern.length; i++) {
+                if (this.buffer[cur + i] != pattern[i]) {
+                    match = false;
+                    break;
+                }
+            }
+            if (match) {
+                return cur;
+            }
+            
+            int pos = cur + pattern.length; 
+            if (pos >= this.buffer.length) {
+                break;
+            }
+            int x = this.buffer[pos] & 0xff;
+            j += shiftTable[x];
+        }
+        return -1;
+    }
+    
+    /**
+     * Implements quick search algorithm as published by
+     * <p> 
+     * SUNDAY D.M., 1990, 
+     * A very fast substring search algorithm, 
+     * Communications of the ACM . 33(8):132-142.
+     * </p>
+     */
+    public int indexOf(final byte[] pattern) {
+        return indexOf(pattern, this.bufpos, this.buflen - this.bufpos);
+    }
+
+    public int indexOf(byte b, int off, int len) {
+        if (off < this.bufpos || len < 0 || off + len > this.buflen) {
+            throw new IndexOutOfBoundsException();
+        }
+        for (int i = off; i < off + len; i++) {
+            if (this.buffer[i] == b) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    
+    public int indexOf(byte b) {
+        return indexOf(b, this.bufpos, this.buflen - this.bufpos);
+    }
+    
+    public byte charAt(int pos) {
+        if (pos < this.bufpos || pos > this.buflen) {
+            throw new IndexOutOfBoundsException();
+        }
+        return this.buffer[pos];
+    }
+    
+    public byte[] buf() {
+        return this.buffer;        
+    }
+    
+    public int pos() {
+        return this.bufpos;
+    }
+    
+    public int limit() {
+        return this.buflen;
+    }
+    
+    public int length() {
+        return this.buflen - this.bufpos;
+    }
+    
+    public int capacity() {
+        return this.buffer.length;
+    }
+    
+    public int skip(int n) {
+        int chunk = Math.min(n, this.buflen - this.bufpos);
+        this.bufpos += chunk; 
+        return chunk;
+    }
+
+    public void clear() {
+        this.bufpos = 0;
+        this.buflen = 0;
+    }
+    
+    @Override
+    public String toString() {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append("[pos: ");
+        buffer.append(this.bufpos);
+        buffer.append("]");
+        buffer.append("[limit: ");
+        buffer.append(this.buflen);
+        buffer.append("]");
+        buffer.append("[");
+        for (int i = this.bufpos; i < this.buflen; i++) {
+            buffer.append((char) this.buffer[i]);
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/EOLConvertingInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/EOLConvertingInputStream.java
new file mode 100644
index 0000000..298ad98
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/EOLConvertingInputStream.java
@@ -0,0 +1,107 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.PushbackInputStream;

+

+/**

+ * InputStream which converts <code>\r</code>

+ * bytes not followed by <code>\n</code> and <code>\n</code> not 

+ * preceded by <code>\r</code> to <code>\r\n</code>.

+ */

+public class EOLConvertingInputStream extends InputStream {

+    /** Converts single '\r' to '\r\n' */

+    public static final int CONVERT_CR   = 1;

+    /** Converts single '\n' to '\r\n' */

+    public static final int CONVERT_LF   = 2;

+    /** Converts single '\r' and '\n' to '\r\n' */

+    public static final int CONVERT_BOTH = 3;

+    

+    private PushbackInputStream in = null;

+    private int previous = 0;

+    private int flags = CONVERT_BOTH;

+    

+    /**

+     * Creates a new <code>EOLConvertingInputStream</code>

+     * instance converting bytes in the given <code>InputStream</code>.

+     * The flag <code>CONVERT_BOTH</code> is the default.

+     * 

+     * @param in the <code>InputStream</code> to read from.

+     */

+    public EOLConvertingInputStream(InputStream in) {

+        this(in, CONVERT_BOTH);

+    }

+    /**

+     * Creates a new <code>EOLConvertingInputStream</code>

+     * instance converting bytes in the given <code>InputStream</code>.

+     * 

+     * @param in the <code>InputStream</code> to read from.

+     * @param flags one of <code>CONVERT_CR</code>, <code>CONVERT_LF</code> or

+     *        <code>CONVERT_BOTH</code>.

+     */

+    public EOLConvertingInputStream(InputStream in, int flags) {

+        super();

+        

+        this.in = new PushbackInputStream(in, 2);

+        this.flags = flags;

+    }

+

+    /**

+     * Closes the underlying stream.

+     * 

+     * @throws IOException on I/O errors.

+     */

+    @Override

+    public void close() throws IOException {

+        in.close();

+    }

+    

+    /**

+     * @see java.io.InputStream#read()

+     */

+    @Override

+    public int read() throws IOException {

+        int b = in.read();

+        

+        if (b == -1) {

+            return -1;

+        }

+        

+        if ((flags & CONVERT_CR) != 0 && b == '\r') {

+            int c = in.read();

+            if (c != -1) {

+                in.unread(c);

+            }

+            if (c != '\n') {

+                in.unread('\n');

+            }

+        } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') {

+            b = '\r';

+            in.unread('\n');

+        }

+        

+        previous = b;

+        

+        return b;

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java
new file mode 100644
index 0000000..dde47eb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LimitedInputStream.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public class LimitedInputStream extends PositionInputStream {
+
+    private final long limit;
+
+    public LimitedInputStream(InputStream instream, long limit) {
+        super(instream);
+        if (limit < 0) {
+            throw new IllegalArgumentException("Limit may not be negative");
+        }
+        this.limit = limit;
+    }
+
+    private void enforceLimit() throws IOException {
+        if (position >= limit) {
+            throw new IOException("Input stream limit exceeded");
+        }
+    }
+    
+    @Override
+    public int read() throws IOException {
+        enforceLimit();
+        return super.read();
+    }
+
+    @Override
+    public int read(byte b[], int off, int len) throws IOException {
+        enforceLimit();
+        len = Math.min(len, getBytesLeft());
+        return super.read(b, off, len);
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        enforceLimit();
+        n = Math.min(n, getBytesLeft());
+        return super.skip(n);
+    }
+
+    private int getBytesLeft() {
+        return (int)Math.min(Integer.MAX_VALUE, limit - position);
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineNumberInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineNumberInputStream.java
new file mode 100644
index 0000000..891f16e
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineNumberInputStream.java
@@ -0,0 +1,67 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import java.io.FilterInputStream;

+import java.io.IOException;

+import java.io.InputStream;

+

+/**

+ * <code>InputStream</code> used by the parser to wrap the original user

+ * supplied stream. This stream keeps track of the current line number.

+ */

+public class LineNumberInputStream extends FilterInputStream implements

+        LineNumberSource {

+    private int lineNumber = 1;

+

+    /**

+     * Creates a new <code>LineNumberInputStream</code>.

+     * 

+     * @param is

+     *            the stream to read from.

+     */

+    public LineNumberInputStream(InputStream is) {

+        super(is);

+    }

+

+    public int getLineNumber() {

+        return lineNumber;

+    }

+

+    @Override

+    public int read() throws IOException {

+        int b = in.read();

+        if (b == '\n') {

+            lineNumber++;

+        }

+        return b;

+    }

+

+    @Override

+    public int read(byte[] b, int off, int len) throws IOException {

+        int n = in.read(b, off, len);

+        for (int i = off; i < off + n; i++) {

+            if (b[i] == '\n') {

+                lineNumber++;

+            }

+        }

+        return n;

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineNumberSource.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineNumberSource.java
new file mode 100644
index 0000000..8006fb3
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineNumberSource.java
@@ -0,0 +1,30 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+public interface LineNumberSource {

+    /**

+     * Gets the current line number starting at 1 (the number of

+     * <code>\r\n</code> read so far plus 1).

+     * 

+     * @return the current line number.

+     */

+    int getLineNumber();

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineReaderInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineReaderInputStream.java
new file mode 100644
index 0000000..905e01d
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineReaderInputStream.java
@@ -0,0 +1,48 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import org.apache.james.mime4j.util.ByteArrayBuffer;

+

+import java.io.FilterInputStream;

+import java.io.IOException;

+import java.io.InputStream;

+

+/**

+ * Input stream capable of reading lines of text. 

+ */

+public abstract class LineReaderInputStream extends FilterInputStream {

+

+    protected LineReaderInputStream(InputStream in) {

+        super(in);

+    }

+

+    /**

+     * Reads one line of text into the given {@link ByteArrayBuffer}.

+     *  

+     * @param dst Destination

+     * @return number of bytes copied or <code>-1</code> if the end of 

+     * the stream has been reached.

+     * 

+     * @throws IOException in case of an I/O error.

+     */

+    public abstract int readLine(final ByteArrayBuffer dst) throws IOException;

+    

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineReaderInputStreamAdaptor.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineReaderInputStreamAdaptor.java
new file mode 100644
index 0000000..e36027f
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/LineReaderInputStreamAdaptor.java
@@ -0,0 +1,118 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <code>InputStream</code> used by the MIME parser to detect whether the
+ * underlying data stream was used (read from) and whether the end of the 
+ * stream was reached.
+ */
+public class LineReaderInputStreamAdaptor extends LineReaderInputStream {
+
+    private final LineReaderInputStream bis;
+    private final int maxLineLen;
+    
+    private boolean used = false;
+    private boolean eof = false;
+
+    public LineReaderInputStreamAdaptor(
+            final InputStream is,
+            int maxLineLen) {
+        super(is);
+        if (is instanceof LineReaderInputStream) {
+            this.bis = (LineReaderInputStream) is;
+        } else {
+            this.bis = null;
+        }
+        this.maxLineLen = maxLineLen;
+    }
+
+    public LineReaderInputStreamAdaptor(
+            final InputStream is) {
+        this(is, -1);
+    }
+    
+    @Override
+    public int read() throws IOException {
+        int i = in.read();
+        this.eof = i == -1;
+        this.used = true;
+        return i;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int i = in.read(b, off, len);
+        this.eof = i == -1;
+        this.used = true;
+        return i;
+    }
+    
+    @Override
+    public int readLine(final ByteArrayBuffer dst) throws IOException {
+        int i;
+        if (this.bis != null) {
+             i = this.bis.readLine(dst);
+        } else {
+             i = doReadLine(dst);
+        }
+        this.eof = i == -1;
+        this.used = true;
+        return i;
+    }
+
+    private int doReadLine(final ByteArrayBuffer dst) throws IOException {
+        int total = 0;
+        int ch;
+        while ((ch = in.read()) != -1) {
+            dst.append(ch);
+            total++;
+            if (this.maxLineLen > 0 && dst.length() >= this.maxLineLen) {
+                throw new MaxLineLimitException("Maximum line length limit exceeded");
+            }
+            if (ch == '\n') {
+                break;
+            }
+        }
+        if (total == 0 && ch == -1) {
+            return -1;
+        } else {
+            return total;
+        }
+    }
+    
+    public boolean eof() {
+        return this.eof;
+    }
+
+    public boolean isUsed() {
+        return this.used;
+    }
+    
+    @Override
+    public String toString() {
+        return "[LineReaderInputStreamAdaptor: " + bis + "]";
+    }
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java
new file mode 100644
index 0000000..7040cd5
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MaxHeaderLimitException.java
@@ -0,0 +1,35 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.MimeException;
+
+/**
+ * Signals a I/O error due to the header count exceeding the maximum limit.
+ */
+public class MaxHeaderLimitException extends MimeException {
+    
+    private static final long serialVersionUID = 2154269045186186769L;
+
+    public MaxHeaderLimitException(final String message) {
+        super(message);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MaxLineLimitException.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MaxLineLimitException.java
new file mode 100644
index 0000000..3534760
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MaxLineLimitException.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.MimeIOException;
+
+/**
+ * Signals a I/O error due to a line exceeding the limit on the 
+ * maximum line length.
+ */
+public class MaxLineLimitException extends MimeIOException {
+    
+    private static final long serialVersionUID = 8039001187837730773L;
+
+    public MaxLineLimitException(final String message) {
+        super(message);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java
new file mode 100644
index 0000000..4c034c1
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java
@@ -0,0 +1,298 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import org.apache.james.mime4j.util.ByteArrayBuffer;

+

+import java.io.IOException;

+

+/**

+ * Stream that constrains itself to a single MIME body part.

+ * After the stream ends (i.e. read() returns -1) {@link #isLastPart()}

+ * can be used to determine if a final boundary has been seen or not.

+ */

+public class MimeBoundaryInputStream extends LineReaderInputStream {

+

+    private final byte[] boundary;

+    

+    private boolean eof;

+    private int limit;

+    private boolean atBoundary;

+    private int boundaryLen;

+    private boolean lastPart;

+    private boolean completed;

+

+    private BufferedLineReaderInputStream buffer;

+

+    /**

+     * Creates a new MimeBoundaryInputStream.

+     * 

+     * @param inbuffer The underlying stream.

+     * @param boundary Boundary string (not including leading hyphens).

+     * @throws IllegalArgumentException when boundary is too long

+     */

+    public MimeBoundaryInputStream(BufferedLineReaderInputStream inbuffer, String boundary) 

+            throws IOException {

+        super(inbuffer);

+        if (inbuffer.capacity() <= boundary.length()) {

+            throw new IllegalArgumentException("Boundary is too long");

+        }

+        this.buffer = inbuffer;

+        this.eof = false;

+        this.limit = -1;

+        this.atBoundary = false;

+        this.boundaryLen = 0;

+        this.lastPart = false;

+        this.completed = false;

+        

+        this.boundary = new byte[boundary.length() + 2];

+        this.boundary[0] = (byte) '-';

+        this.boundary[1] = (byte) '-';

+        for (int i = 0; i < boundary.length(); i++) {

+            byte ch = (byte) boundary.charAt(i);

+            if (ch == '\r' || ch == '\n') {

+                throw new IllegalArgumentException("Boundary may not contain CR or LF");

+            }

+            this.boundary[i + 2] = ch;

+        }

+        fillBuffer();

+    }

+

+    /**

+     * Closes the underlying stream.

+     * 

+     * @throws IOException on I/O errors.

+     */

+    @Override

+    public void close() throws IOException {

+    }

+

+    /**

+     * @see java.io.InputStream#markSupported()

+     */

+    @Override

+    public boolean markSupported() {

+        return false;

+    }

+

+    /**

+     * @see java.io.InputStream#read()

+     */

+    @Override

+    public int read() throws IOException {

+        if (completed) {

+            return -1;

+        }

+        if (endOfStream() && !hasData()) {

+            skipBoundary();            

+            return -1;

+        }

+        for (;;) {

+            if (hasData()) {

+                return buffer.read();

+            } else if (endOfStream()) {

+                skipBoundary();            

+                return -1;

+            }

+            fillBuffer();

+        }

+    }

+    

+    @Override

+    public int read(byte[] b, int off, int len) throws IOException {

+        if (completed) {

+            return -1;

+        }

+        if (endOfStream() && !hasData()) {

+            skipBoundary();            

+            return -1;

+        }

+        fillBuffer();

+        if (!hasData()) {

+            return read(b, off, len);

+        }

+        int chunk = Math.min(len, limit - buffer.pos());

+        return buffer.read(b, off, chunk);

+    }

+

+    @Override

+    public int readLine(final ByteArrayBuffer dst) throws IOException {

+        if (dst == null) {

+            throw new IllegalArgumentException("Destination buffer may not be null");

+        }

+        if (completed) {

+            return -1;

+        }

+        if (endOfStream() && !hasData()) {

+            skipBoundary();            

+            return -1;

+        }

+

+        int total = 0;

+        boolean found = false;

+        int bytesRead = 0;

+        while (!found) {

+            if (!hasData()) {

+                bytesRead = fillBuffer();

+                if (!hasData() && endOfStream()) {

+                    skipBoundary();

+                    bytesRead = -1;

+                    break;

+                }

+            }

+            int len = this.limit - this.buffer.pos();

+            int i = this.buffer.indexOf((byte)'\n', this.buffer.pos(), len);

+            int chunk;

+            if (i != -1) {

+                found = true;

+                chunk = i + 1 - this.buffer.pos();

+            } else {

+                chunk = len;

+            }

+            if (chunk > 0) {

+                dst.append(this.buffer.buf(), this.buffer.pos(), chunk);

+                this.buffer.skip(chunk);

+                total += chunk;

+            }

+        }

+        if (total == 0 && bytesRead == -1) {

+            return -1;

+        } else {

+            return total;

+        }

+    }

+    

+    private boolean endOfStream() {

+        return eof || atBoundary;

+    }

+    

+    private boolean hasData() {

+        return limit > buffer.pos() && limit <= buffer.limit();

+    }

+    

+    private int fillBuffer() throws IOException {

+        if (eof) {

+            return -1;

+        }

+        int bytesRead;

+        if (!hasData()) {

+            bytesRead = buffer.fillBuffer();

+        } else {

+            bytesRead = 0;

+        }

+        eof = bytesRead == -1;

+        

+        

+        int i = buffer.indexOf(boundary);

+        // NOTE this currently check only for LF. It doesn't check for canonical CRLF

+        // and neither for isolated CR. This will require updates according to MIME4J-60

+        while (i > 0 && buffer.charAt(i-1) != '\n') {

+            // skip the "fake" boundary (it does not contain LF or CR so we cannot have

+            // another boundary starting before this is complete.

+            i = i + boundary.length;

+            i = buffer.indexOf(boundary, i, buffer.limit() - i);

+        }

+        if (i != -1) {

+            limit = i;

+            atBoundary = true;

+            calculateBoundaryLen();

+        } else {

+            if (eof) {

+                limit = buffer.limit();

+            } else {

+                limit = buffer.limit() - (boundary.length + 1); 

+                                          // \r\n + (boundary - one char)

+            }

+        }

+        return bytesRead;

+    }

+    

+    private void calculateBoundaryLen() throws IOException {

+        boundaryLen = boundary.length;

+        int len = limit - buffer.pos();

+        if (len > 0) {

+            if (buffer.charAt(limit - 1) == '\n') {

+                boundaryLen++;

+                limit--;

+            }

+        }

+        if (len > 1) {

+            if (buffer.charAt(limit - 1) == '\r') {

+                boundaryLen++;

+                limit--;

+            }

+        }

+    }

+    

+    private void skipBoundary() throws IOException {

+        if (!completed) {

+            completed = true;

+            buffer.skip(boundaryLen);

+            boolean checkForLastPart = true;

+            for (;;) {

+                if (buffer.length() > 1) {

+                    int ch1 = buffer.charAt(buffer.pos());

+                    int ch2 = buffer.charAt(buffer.pos() + 1);

+                    

+                    if (checkForLastPart) if (ch1 == '-' && ch2 == '-') {

+                        this.lastPart = true;

+                        buffer.skip(2);

+                        checkForLastPart = false;

+                        continue;

+                    }

+                    

+                    if (ch1 == '\r' && ch2 == '\n') {

+                        buffer.skip(2);

+                        break;

+                    } else if (ch1 == '\n') {

+                        buffer.skip(1);

+                        break;

+                    } else {

+                        // ignoring everything in a line starting with a boundary.

+                        buffer.skip(1);

+                    }

+                    

+                } else {

+                    if (eof) {

+                        break;

+                    }

+                    fillBuffer();

+                }

+            }

+        }

+    }

+    

+    public boolean isLastPart() {

+        return lastPart;        

+    }

+    

+    public boolean eof() {

+        return eof && !buffer.hasBufferedData();

+    }

+

+    @Override

+    public String toString() {

+        final StringBuilder buffer = new StringBuilder("MimeBoundaryInputStream, boundary ");

+        for (byte b : boundary) {

+            buffer.append((char) b);

+        }

+        return buffer.toString();

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java
new file mode 100644
index 0000000..7fef9e5
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/io/PositionInputStream.java
@@ -0,0 +1,91 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+

+package org.apache.james.mime4j.io;

+

+import java.io.FilterInputStream;

+import java.io.InputStream;

+import java.io.IOException;

+

+public class PositionInputStream extends FilterInputStream {

+

+    protected long position = 0;

+    private long markedPosition = 0;

+

+    public PositionInputStream(InputStream inputStream) {

+        super(inputStream);

+    }

+

+    public long getPosition() {

+        return position;

+    }

+

+    @Override

+    public int available() throws IOException {

+        return in.available();

+    }

+

+    @Override

+    public int read() throws IOException {

+        int b = in.read();

+        if (b != -1)

+            position++;

+        return b;

+    }

+

+    @Override

+    public void close() throws IOException {

+        in.close();

+    }

+

+    @Override

+    public void reset() throws IOException {

+        in.reset();

+        position = markedPosition;

+    }

+

+    @Override

+    public boolean markSupported() {

+        return in.markSupported();

+    }

+

+    @Override

+    public void mark(int readlimit) {

+        in.mark(readlimit);

+        markedPosition = position;

+    }

+

+    @Override

+    public long skip(long n) throws IOException {

+        final long c = in.skip(n);

+        if (c > 0) 

+            position += c;

+        return c;

+    }

+

+    @Override

+    public int read(byte b[], int off, int len) throws IOException {

+        final int c = in.read(b, off, len);

+        if (c > 0) 

+            position += c;

+        return c;

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BinaryBody.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BinaryBody.java
new file mode 100644
index 0000000..5f0e0fa
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BinaryBody.java
@@ -0,0 +1,45 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.message;

+

+import java.io.IOException;

+import java.io.InputStream;

+

+/**

+ * A body containing binary data.

+ */

+public abstract class BinaryBody extends SingleBody {

+

+    /**

+     * Sole constructor.

+     */

+    protected BinaryBody() {

+    }

+

+    /**

+     * Gets a <code>InputStream</code> which reads the bytes of the body.

+     * 

+     * @return the stream, transfer decoded

+     * @throws IOException

+     *             on I/O errors.

+     */

+    public abstract InputStream getInputStream() throws IOException;

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Body.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Body.java
new file mode 100644
index 0000000..48a8070
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Body.java
@@ -0,0 +1,46 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.message;

+

+/**

+ * Encapsulates the body of an entity (see RFC 2045).

+ * <p>

+ * A body can be a {@link Message}, a {@link Multipart} or a {@link SingleBody}.

+ * This interface should not be implemented directly by classes other than

+ * those.

+ */

+public interface Body extends Disposable {

+

+    /**

+     * Gets the parent of this body.

+     * 

+     * @return the parent.

+     */

+    Entity getParent();

+

+    /**

+     * Sets the parent of this body.

+     * 

+     * @param parent

+     *            the parent.

+     */

+    void setParent(Entity parent);

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyCopier.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyCopier.java
new file mode 100644
index 0000000..0da34f9
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyCopier.java
@@ -0,0 +1,68 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+/**
+ * Utility class for copying message bodies.
+ */
+public class BodyCopier {
+
+    private BodyCopier() {
+    }
+
+    /**
+     * Returns a copy of the given {@link Body} that can be used (and modified)
+     * independently of the original. The copy should be
+     * {@link Disposable#dispose() disposed of} when it is no longer needed.
+     * <p>
+     * The {@link Body#getParent() parent} of the returned copy is
+     * <code>null</code>, that is, the copy is detached from the parent
+     * entity of the original.
+     * 
+     * @param body
+     *            body to copy.
+     * @return a copy of the given body.
+     * @throws UnsupportedOperationException
+     *             if <code>body</code> is an instance of {@link SingleBody}
+     *             that does not support the {@link SingleBody#copy() copy()}
+     *             operation (or contains such a <code>SingleBody</code>).
+     * @throws IllegalArgumentException
+     *             if <code>body</code> is <code>null</code> or
+     *             <code>body</code> is a <code>Body</code> that is neither
+     *             a {@link Message}, {@link Multipart} or {@link SingleBody}
+     *             (or contains such a <code>Body</code>).
+     */
+    public static Body copy(Body body) {
+        if (body == null)
+            throw new IllegalArgumentException("Body is null");
+
+        if (body instanceof Message)
+            return new Message((Message) body);
+
+        if (body instanceof Multipart)
+            return new Multipart((Multipart) body);
+
+        if (body instanceof SingleBody)
+            return ((SingleBody) body).copy();
+
+        throw new IllegalArgumentException("Unsupported body class");
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyFactory.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
new file mode 100644
index 0000000..954d3ba
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
@@ -0,0 +1,310 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.james.mime4j.storage.DefaultStorageProvider;
+import org.apache.james.mime4j.storage.MultiReferenceStorage;
+import org.apache.james.mime4j.storage.Storage;
+import org.apache.james.mime4j.storage.StorageProvider;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Factory for creating message bodies.
+ */
+public class BodyFactory {
+
+    private static Log log = LogFactory.getLog(BodyFactory.class);
+
+    private static final Charset FALLBACK_CHARSET = CharsetUtil.DEFAULT_CHARSET;
+
+    private StorageProvider storageProvider;
+
+    /**
+     * Creates a new <code>BodyFactory</code> instance that uses the default
+     * storage provider for creating message bodies from input streams.
+     */
+    public BodyFactory() {
+        this.storageProvider = DefaultStorageProvider.getInstance();
+    }
+
+    /**
+     * Creates a new <code>BodyFactory</code> instance that uses the given
+     * storage provider for creating message bodies from input streams.
+     * 
+     * @param storageProvider
+     *            a storage provider or <code>null</code> to use the default
+     *            one.
+     */
+    public BodyFactory(StorageProvider storageProvider) {
+        if (storageProvider == null)
+            storageProvider = DefaultStorageProvider.getInstance();
+
+        this.storageProvider = storageProvider;
+    }
+
+    /**
+     * Returns the <code>StorageProvider</code> this <code>BodyFactory</code>
+     * uses to create message bodies from input streams.
+     * 
+     * @return a <code>StorageProvider</code>.
+     */
+    public StorageProvider getStorageProvider() {
+        return storageProvider;
+    }
+
+    /**
+     * Creates a {@link BinaryBody} that holds the content of the given input
+     * stream.
+     * 
+     * @param is
+     *            input stream to create a message body from.
+     * @return a binary body.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public BinaryBody binaryBody(InputStream is) throws IOException {
+        if (is == null)
+            throw new IllegalArgumentException();
+
+        Storage storage = storageProvider.store(is);
+        return new StorageBinaryBody(new MultiReferenceStorage(storage));
+    }
+
+    /**
+     * Creates a {@link BinaryBody} that holds the content of the given
+     * {@link Storage}.
+     * <p>
+     * Note that the caller must not invoke {@link Storage#delete() delete()} on
+     * the given <code>Storage</code> object after it has been passed to this
+     * method. Instead the message body created by this method takes care of
+     * deleting the storage when it gets disposed of (see
+     * {@link Disposable#dispose()}).
+     * 
+     * @param storage
+     *            storage to create a message body from.
+     * @return a binary body.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public BinaryBody binaryBody(Storage storage) throws IOException {
+        if (storage == null)
+            throw new IllegalArgumentException();
+
+        return new StorageBinaryBody(new MultiReferenceStorage(storage));
+    }
+
+    /**
+     * Creates a {@link TextBody} that holds the content of the given input
+     * stream.
+     * <p>
+     * &quot;us-ascii&quot; is used to decode the byte content of the
+     * <code>Storage</code> into a character stream when calling
+     * {@link TextBody#getReader() getReader()} on the returned object.
+     * 
+     * @param is
+     *            input stream to create a message body from.
+     * @return a text body.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public TextBody textBody(InputStream is) throws IOException {
+        if (is == null)
+            throw new IllegalArgumentException();
+
+        Storage storage = storageProvider.store(is);
+        return new StorageTextBody(new MultiReferenceStorage(storage),
+                CharsetUtil.DEFAULT_CHARSET);
+    }
+
+    /**
+     * Creates a {@link TextBody} that holds the content of the given input
+     * stream.
+     * <p>
+     * The charset corresponding to the given MIME charset name is used to
+     * decode the byte content of the input stream into a character stream when
+     * calling {@link TextBody#getReader() getReader()} on the returned object.
+     * If the MIME charset has no corresponding Java charset or the Java charset
+     * cannot be used for decoding then &quot;us-ascii&quot; is used instead.
+     * 
+     * @param is
+     *            input stream to create a message body from.
+     * @param mimeCharset
+     *            name of a MIME charset.
+     * @return a text body.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public TextBody textBody(InputStream is, String mimeCharset)
+            throws IOException {
+        if (is == null)
+            throw new IllegalArgumentException();
+        if (mimeCharset == null)
+            throw new IllegalArgumentException();
+
+        Storage storage = storageProvider.store(is);
+        Charset charset = toJavaCharset(mimeCharset, false);
+        return new StorageTextBody(new MultiReferenceStorage(storage), charset);
+    }
+
+    /**
+     * Creates a {@link TextBody} that holds the content of the given
+     * {@link Storage}.
+     * <p>
+     * &quot;us-ascii&quot; is used to decode the byte content of the
+     * <code>Storage</code> into a character stream when calling
+     * {@link TextBody#getReader() getReader()} on the returned object.
+     * <p>
+     * Note that the caller must not invoke {@link Storage#delete() delete()} on
+     * the given <code>Storage</code> object after it has been passed to this
+     * method. Instead the message body created by this method takes care of
+     * deleting the storage when it gets disposed of (see
+     * {@link Disposable#dispose()}).
+     * 
+     * @param storage
+     *            storage to create a message body from.
+     * @return a text body.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public TextBody textBody(Storage storage) throws IOException {
+        if (storage == null)
+            throw new IllegalArgumentException();
+
+        return new StorageTextBody(new MultiReferenceStorage(storage),
+                CharsetUtil.DEFAULT_CHARSET);
+    }
+
+    /**
+     * Creates a {@link TextBody} that holds the content of the given
+     * {@link Storage}.
+     * <p>
+     * The charset corresponding to the given MIME charset name is used to
+     * decode the byte content of the <code>Storage</code> into a character
+     * stream when calling {@link TextBody#getReader() getReader()} on the
+     * returned object. If the MIME charset has no corresponding Java charset or
+     * the Java charset cannot be used for decoding then &quot;us-ascii&quot; is
+     * used instead.
+     * <p>
+     * Note that the caller must not invoke {@link Storage#delete() delete()} on
+     * the given <code>Storage</code> object after it has been passed to this
+     * method. Instead the message body created by this method takes care of
+     * deleting the storage when it gets disposed of (see
+     * {@link Disposable#dispose()}).
+     * 
+     * @param storage
+     *            storage to create a message body from.
+     * @param mimeCharset
+     *            name of a MIME charset.
+     * @return a text body.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public TextBody textBody(Storage storage, String mimeCharset)
+            throws IOException {
+        if (storage == null)
+            throw new IllegalArgumentException();
+        if (mimeCharset == null)
+            throw new IllegalArgumentException();
+
+        Charset charset = toJavaCharset(mimeCharset, false);
+        return new StorageTextBody(new MultiReferenceStorage(storage), charset);
+    }
+
+    /**
+     * Creates a {@link TextBody} that holds the content of the given string.
+     * <p>
+     * &quot;us-ascii&quot; is used to encode the characters of the string into
+     * a byte stream when calling
+     * {@link SingleBody#writeTo(java.io.OutputStream) writeTo(OutputStream)} on
+     * the returned object.
+     * 
+     * @param text
+     *            text to create a message body from.
+     * @return a text body.
+     */
+    public TextBody textBody(String text) {
+        if (text == null)
+            throw new IllegalArgumentException();
+
+        return new StringTextBody(text, CharsetUtil.DEFAULT_CHARSET);
+    }
+
+    /**
+     * Creates a {@link TextBody} that holds the content of the given string.
+     * <p>
+     * The charset corresponding to the given MIME charset name is used to
+     * encode the characters of the string into a byte stream when calling
+     * {@link SingleBody#writeTo(java.io.OutputStream) writeTo(OutputStream)} on
+     * the returned object. If the MIME charset has no corresponding Java
+     * charset or the Java charset cannot be used for encoding then
+     * &quot;us-ascii&quot; is used instead.
+     * 
+     * @param text
+     *            text to create a message body from.
+     * @param mimeCharset
+     *            name of a MIME charset.
+     * @return a text body.
+     */
+    public TextBody textBody(String text, String mimeCharset) {
+        if (text == null)
+            throw new IllegalArgumentException();
+        if (mimeCharset == null)
+            throw new IllegalArgumentException();
+
+        Charset charset = toJavaCharset(mimeCharset, true);
+        return new StringTextBody(text, charset);
+    }
+
+    private static Charset toJavaCharset(String mimeCharset, boolean forEncoding) {
+        String charset = CharsetUtil.toJavaCharset(mimeCharset);
+        if (charset == null) {
+            if (log.isWarnEnabled())
+                log.warn("MIME charset '" + mimeCharset + "' has no "
+                        + "corresponding Java charset. Using "
+                        + FALLBACK_CHARSET + " instead.");
+            return FALLBACK_CHARSET;
+        }
+
+        if (forEncoding && !CharsetUtil.isEncodingSupported(charset)) {
+            if (log.isWarnEnabled())
+                log.warn("MIME charset '" + mimeCharset
+                        + "' does not support encoding. Using "
+                        + FALLBACK_CHARSET + " instead.");
+            return FALLBACK_CHARSET;
+        }
+
+        if (!forEncoding && !CharsetUtil.isDecodingSupported(charset)) {
+            if (log.isWarnEnabled())
+                log.warn("MIME charset '" + mimeCharset
+                        + "' does not support decoding. Using "
+                        + FALLBACK_CHARSET + " instead.");
+            return FALLBACK_CHARSET;
+        }
+
+        return Charset.forName(charset);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyPart.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyPart.java
new file mode 100644
index 0000000..789dd06
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/BodyPart.java
@@ -0,0 +1,54 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.message;

+

+/**

+ * Represents a MIME body part  (see RFC 2045).

+ */

+public class BodyPart extends Entity {

+

+    /**

+     * Creates a new empty <code>BodyPart</code>.

+     */

+    public BodyPart() {

+    }

+

+    /**

+     * Creates a new <code>BodyPart</code> from the specified

+     * <code>BodyPart</code>. The <code>BodyPart</code> instance is initialized

+     * with copies of header and body of the specified <code>BodyPart</code>.

+     * The parent entity of the new body part is <code>null</code>.

+     * 

+     * @param other

+     *            body part to copy.

+     * @throws UnsupportedOperationException

+     *             if <code>other</code> contains a {@link SingleBody} that

+     *             does not support the {@link SingleBody#copy() copy()}

+     *             operation.

+     * @throws IllegalArgumentException

+     *             if <code>other</code> contains a <code>Body</code> that

+     *             is neither a {@link Message}, {@link Multipart} or

+     *             {@link SingleBody}.

+     */

+    public BodyPart(BodyPart other) {

+        super(other);

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Disposable.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Disposable.java
new file mode 100644
index 0000000..96c5617
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Disposable.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+/**
+ * A <tt>Disposable</tt> is an object that should be disposed of explicitly
+ * when it is no longer needed.
+ * 
+ * The dispose method is invoked to release resources that the object is
+ * holding (such as open files). 
+ */
+public interface Disposable {
+    /**
+     * Free any resources this object is holding and prepares this object
+     * for garbage collection. Once an object has been disposed of it can no
+     * longer be used.
+     */
+    void dispose();
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Entity.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Entity.java
new file mode 100644
index 0000000..56a12d4
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Entity.java
@@ -0,0 +1,557 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.james.mime4j.field.ContentDispositionField;
+import org.apache.james.mime4j.field.ContentTransferEncodingField;
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.FieldName;
+import org.apache.james.mime4j.field.Fields;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * MIME entity. An entity has a header and a body (see RFC 2045).
+ */
+public abstract class Entity implements Disposable {
+    private Header header = null;
+    private Body body = null;
+    private Entity parent = null;
+
+    /**
+     * Creates a new <code>Entity</code>. Typically invoked implicitly by a
+     * subclass constructor.
+     */
+    protected Entity() {
+    }
+
+    /**
+     * Creates a new <code>Entity</code> from the specified
+     * <code>Entity</code>. The <code>Entity</code> instance is initialized
+     * with copies of header and body of the specified <code>Entity</code>.
+     * The parent entity of the new entity is <code>null</code>.
+     * 
+     * @param other
+     *            entity to copy.
+     * @throws UnsupportedOperationException
+     *             if <code>other</code> contains a {@link SingleBody} that
+     *             does not support the {@link SingleBody#copy() copy()}
+     *             operation.
+     * @throws IllegalArgumentException
+     *             if <code>other</code> contains a <code>Body</code> that
+     *             is neither a {@link Message}, {@link Multipart} or
+     *             {@link SingleBody}.
+     */
+    protected Entity(Entity other) {
+        if (other.header != null) {
+            header = new Header(other.header);
+        }
+
+        if (other.body != null) {
+            Body bodyCopy = BodyCopier.copy(other.body);
+            setBody(bodyCopy);
+        }
+    }
+
+    /**
+     * Gets the parent entity of this entity.
+     * Returns <code>null</code> if this is the root entity.
+     * 
+     * @return the parent or <code>null</code>.
+     */
+    public Entity getParent() {
+        return parent;
+    }
+    
+    /**
+     * Sets the parent entity of this entity.
+     * 
+     * @param parent the parent entity or <code>null</code> if
+     *        this will be the root entity.
+     */
+    public void setParent(Entity parent) {
+        this.parent = parent;
+    }
+    
+    /**
+     * Gets the entity header.
+     * 
+     * @return the header.
+     */
+    public Header getHeader() {
+        return header;
+    }
+    
+    /**
+     * Sets the entity header.
+     * 
+     * @param header the header.
+     */
+    public void setHeader(Header header) {
+        this.header = header;
+    }
+    
+    /**
+     * Gets the body of this entity.
+     * 
+     * @return the body,
+     */
+    public Body getBody() {
+        return body;
+    }
+
+    /**
+     * Sets the body of this entity.
+     * 
+     * @param body the body.
+     * @throws IllegalStateException if the body has already been set.
+     */
+    public void setBody(Body body) {
+        if (this.body != null)
+            throw new IllegalStateException("body already set");
+
+        this.body = body;
+        body.setParent(this);
+    }
+
+    /**
+     * Removes and returns the body of this entity. The removed body may be
+     * attached to another entity. If it is no longer needed it should be
+     * {@link Disposable#dispose() disposed} of.
+     * 
+     * @return the removed body or <code>null</code> if no body was set.
+     */
+    public Body removeBody() {
+        if (body == null)
+            return null;
+
+        Body body = this.body;
+        this.body = null;
+        body.setParent(null);
+
+        return body;
+    }
+
+    /**
+     * Sets the specified message as body of this entity and the content type to
+     * &quot;message/rfc822&quot;. A <code>Header</code> is created if this
+     * entity does not already have one.
+     * 
+     * @param message
+     *            the message to set as body.
+     */
+    public void setMessage(Message message) {
+        setBody(message, "message/rfc822", null);
+    }
+
+    /**
+     * Sets the specified multipart as body of this entity. Also sets the
+     * content type accordingly and creates a message boundary string. A
+     * <code>Header</code> is created if this entity does not already have
+     * one.
+     * 
+     * @param multipart
+     *            the multipart to set as body.
+     */
+    public void setMultipart(Multipart multipart) {
+        String mimeType = "multipart/" + multipart.getSubType();
+        Map<String, String> parameters = Collections.singletonMap("boundary",
+                MimeUtil.createUniqueBoundary());
+
+        setBody(multipart, mimeType, parameters);
+    }
+
+    /**
+     * Sets the specified multipart as body of this entity. Also sets the
+     * content type accordingly and creates a message boundary string. A
+     * <code>Header</code> is created if this entity does not already have
+     * one.
+     * 
+     * @param multipart
+     *            the multipart to set as body.
+     * @param parameters
+     *            additional parameters for the Content-Type header field.
+     */
+    public void setMultipart(Multipart multipart, Map<String, String> parameters) {
+        String mimeType = "multipart/" + multipart.getSubType();
+        if (!parameters.containsKey("boundary")) {
+            parameters = new HashMap<String, String>(parameters);
+            parameters.put("boundary", MimeUtil.createUniqueBoundary());
+        }
+
+        setBody(multipart, mimeType, parameters);
+    }
+
+    /**
+     * Sets the specified <code>TextBody</code> as body of this entity and the
+     * content type to &quot;text/plain&quot;. A <code>Header</code> is
+     * created if this entity does not already have one.
+     * 
+     * @param textBody
+     *            the <code>TextBody</code> to set as body.
+     * @see BodyFactory#textBody(String)
+     */
+    public void setText(TextBody textBody) {
+        setText(textBody, "plain");
+    }
+
+    /**
+     * Sets the specified <code>TextBody</code> as body of this entity. Also
+     * sets the content type according to the specified sub-type. A
+     * <code>Header</code> is created if this entity does not already have
+     * one.
+     * 
+     * @param textBody
+     *            the <code>TextBody</code> to set as body.
+     * @param subtype
+     *            the text subtype (e.g. &quot;plain&quot;, &quot;html&quot; or
+     *            &quot;xml&quot;).
+     * @see BodyFactory#textBody(String)
+     */
+    public void setText(TextBody textBody, String subtype) {
+        String mimeType = "text/" + subtype;
+
+        Map<String, String> parameters = null;
+        String mimeCharset = textBody.getMimeCharset();
+        if (mimeCharset != null && !mimeCharset.equalsIgnoreCase("us-ascii")) {
+            parameters = Collections.singletonMap("charset", mimeCharset);
+        }
+
+        setBody(textBody, mimeType, parameters);
+    }
+
+    /**
+     * Sets the body of this entity and sets the content-type to the specified
+     * value. A <code>Header</code> is created if this entity does not already
+     * have one.
+     * 
+     * @param body
+     *            the body.
+     * @param mimeType
+     *            the MIME media type of the specified body
+     *            (&quot;type/subtype&quot;).
+     */
+    public void setBody(Body body, String mimeType) {
+        setBody(body, mimeType, null);
+    }
+
+    /**
+     * Sets the body of this entity and sets the content-type to the specified
+     * value. A <code>Header</code> is created if this entity does not already
+     * have one.
+     * 
+     * @param body
+     *            the body.
+     * @param mimeType
+     *            the MIME media type of the specified body
+     *            (&quot;type/subtype&quot;).
+     * @param parameters
+     *            additional parameters for the Content-Type header field.
+     */
+    public void setBody(Body body, String mimeType,
+            Map<String, String> parameters) {
+        setBody(body);
+
+        Header header = obtainHeader();
+        header.setField(Fields.contentType(mimeType, parameters));
+    }
+
+    /**
+     * Determines the MIME type of this <code>Entity</code>. The MIME type
+     * is derived by looking at the parent's Content-Type field if no
+     * Content-Type field is set for this <code>Entity</code>.
+     * 
+     * @return the MIME type.
+     */
+    public String getMimeType() {
+        ContentTypeField child = 
+            (ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE);
+        ContentTypeField parent = getParent() != null 
+            ? (ContentTypeField) getParent().getHeader().
+                                                getField(FieldName.CONTENT_TYPE)
+            : null;
+        
+        return ContentTypeField.getMimeType(child, parent);
+    }
+    
+    /**
+     * Determines the MIME character set encoding of this <code>Entity</code>.
+     * 
+     * @return the MIME character set encoding.
+     */
+    public String getCharset() {
+        return ContentTypeField.getCharset( 
+            (ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE));
+    }
+    
+    /**
+     * Determines the transfer encoding of this <code>Entity</code>.
+     * 
+     * @return the transfer encoding.
+     */
+    public String getContentTransferEncoding() {
+        ContentTransferEncodingField f = (ContentTransferEncodingField) 
+                        getHeader().getField(FieldName.CONTENT_TRANSFER_ENCODING);
+        
+        return ContentTransferEncodingField.getEncoding(f);
+    }
+
+    /**
+     * Sets the transfer encoding of this <code>Entity</code> to the specified
+     * value.
+     * 
+     * @param contentTransferEncoding
+     *            transfer encoding to use.
+     */
+    public void setContentTransferEncoding(String contentTransferEncoding) {
+        Header header = obtainHeader();
+        header.setField(Fields.contentTransferEncoding(contentTransferEncoding));
+    }
+
+    /**
+     * Return the disposition type of the content disposition of this
+     * <code>Entity</code>.
+     * 
+     * @return the disposition type or <code>null</code> if no disposition
+     *         type has been set.
+     */
+    public String getDispositionType() {
+        ContentDispositionField field = obtainField(FieldName.CONTENT_DISPOSITION);
+        if (field == null)
+            return null;
+
+        return field.getDispositionType();
+    }
+    
+    /**
+     * Sets the content disposition of this <code>Entity</code> to the
+     * specified disposition type. No filename, size or date parameters
+     * are included in the content disposition.
+     * 
+     * @param dispositionType
+     *            disposition type value (usually <code>inline</code> or
+     *            <code>attachment</code>).
+     */
+    public void setContentDisposition(String dispositionType) {
+        Header header = obtainHeader();
+        header.setField(Fields.contentDisposition(dispositionType, null, -1,
+                null, null, null));
+    }
+
+    /**
+     * Sets the content disposition of this <code>Entity</code> to the
+     * specified disposition type and filename. No size or date parameters are
+     * included in the content disposition.
+     * 
+     * @param dispositionType
+     *            disposition type value (usually <code>inline</code> or
+     *            <code>attachment</code>).
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     */
+    public void setContentDisposition(String dispositionType, String filename) {
+        Header header = obtainHeader();
+        header.setField(Fields.contentDisposition(dispositionType, filename,
+                -1, null, null, null));
+    }
+
+    /**
+     * Sets the content disposition of this <code>Entity</code> to the
+     * specified values. No date parameters are included in the content
+     * disposition.
+     * 
+     * @param dispositionType
+     *            disposition type value (usually <code>inline</code> or
+     *            <code>attachment</code>).
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @param size
+     *            size parameter value or <code>-1</code> if the parameter
+     *            should not be included.
+     */
+    public void setContentDisposition(String dispositionType, String filename,
+            long size) {
+        Header header = obtainHeader();
+        header.setField(Fields.contentDisposition(dispositionType, filename,
+                size, null, null, null));
+    }
+
+    /**
+     * Sets the content disposition of this <code>Entity</code> to the
+     * specified values.
+     * 
+     * @param dispositionType
+     *            disposition type value (usually <code>inline</code> or
+     *            <code>attachment</code>).
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @param size
+     *            size parameter value or <code>-1</code> if the parameter
+     *            should not be included.
+     * @param creationDate
+     *            creation-date parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     * @param modificationDate
+     *            modification-date parameter value or <code>null</code> if
+     *            the parameter should not be included.
+     * @param readDate
+     *            read-date parameter value or <code>null</code> if the
+     *            parameter should not be included.
+     */
+    public void setContentDisposition(String dispositionType, String filename,
+            long size, Date creationDate, Date modificationDate, Date readDate) {
+        Header header = obtainHeader();
+        header.setField(Fields.contentDisposition(dispositionType, filename,
+                size, creationDate, modificationDate, readDate));
+    }
+
+    /**
+     * Returns the filename parameter of the content disposition of this
+     * <code>Entity</code>.
+     * 
+     * @return the filename parameter of the content disposition or
+     *         <code>null</code> if the filename has not been set.
+     */
+    public String getFilename() {
+        ContentDispositionField field = obtainField(FieldName.CONTENT_DISPOSITION);
+        if (field == null)
+            return null;
+
+        return field.getFilename();
+    }
+    
+    /**
+     * Sets the filename parameter of the content disposition of this
+     * <code>Entity</code> to the specified value. If this entity does not
+     * have a content disposition header field a new one with disposition type
+     * <code>attachment</code> is created.
+     * 
+     * @param filename
+     *            filename parameter value or <code>null</code> if the
+     *            parameter should be removed.
+     */
+    public void setFilename(String filename) {
+        Header header = obtainHeader();
+        ContentDispositionField field = (ContentDispositionField) header
+                .getField(FieldName.CONTENT_DISPOSITION);
+        if (field == null) {
+            if (filename != null) {
+                header.setField(Fields.contentDisposition(
+                        ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT,
+                        filename, -1, null, null, null));
+            }
+        } else {
+            String dispositionType = field.getDispositionType();
+            Map<String, String> parameters = new HashMap<String, String>(field
+                    .getParameters());
+            if (filename == null) {
+                parameters.remove(ContentDispositionField.PARAM_FILENAME);
+            } else {
+                parameters
+                        .put(ContentDispositionField.PARAM_FILENAME, filename);
+            }
+            header.setField(Fields.contentDisposition(dispositionType,
+                    parameters));
+        }
+    }
+
+    /**
+     * Determines if the MIME type of this <code>Entity</code> matches the
+     * given one. MIME types are case-insensitive.
+     * 
+     * @param type the MIME type to match against.
+     * @return <code>true</code> on match, <code>false</code> otherwise.
+     */
+    public boolean isMimeType(String type) {
+        return getMimeType().equalsIgnoreCase(type);
+    }
+    
+    /**
+     * Determines if the MIME type of this <code>Entity</code> is
+     * <code>multipart/*</code>. Since multipart-entities must have
+     * a boundary parameter in the <code>Content-Type</code> field this
+     * method returns <code>false</code> if no boundary exists.
+     * 
+     * @return <code>true</code> on match, <code>false</code> otherwise.
+     */
+    public boolean isMultipart() {
+        ContentTypeField f = 
+            (ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE);
+        return f != null && f.getBoundary() != null 
+            && getMimeType().startsWith(ContentTypeField.TYPE_MULTIPART_PREFIX);
+    }
+
+    /**
+     * Disposes of the body of this entity. Note that the dispose call does not
+     * get forwarded to the parent entity of this Entity.
+     * 
+     * Subclasses that need to free resources should override this method and
+     * invoke super.dispose().
+     * 
+     * @see org.apache.james.mime4j.message.Disposable#dispose()
+     */
+    public void dispose() {
+        if (body != null) {
+            body.dispose();
+        }
+    }
+
+    /**
+     * Obtains the header of this entity. Creates and sets a new header if this
+     * entity's header is currently <code>null</code>.
+     * 
+     * @return the header of this entity; never <code>null</code>.
+     */
+    Header obtainHeader() {
+        if (header == null) {
+            header = new Header();
+        }
+        return header;
+    }
+
+    /**
+     * Obtains the header field with the specified name.
+     * 
+     * @param <F>
+     *            concrete field type.
+     * @param fieldName
+     *            name of the field to retrieve.
+     * @return the header field or <code>null</code> if this entity has no
+     *         header or the header contains no such field.
+     */
+    <F extends Field> F obtainField(String fieldName) {
+        Header header = getHeader();
+        if (header == null)
+            return null;
+
+        @SuppressWarnings("unchecked")
+        F field = (F) header.getField(fieldName);
+        return field;
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Header.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Header.java
new file mode 100644
index 0000000..c2a23ee
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Header.java
@@ -0,0 +1,238 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.parser.AbstractContentHandler;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+
+/**
+ * The header of an entity (see RFC 2045).
+ */
+public class Header implements Iterable<Field> {
+
+    private List<Field> fields = new LinkedList<Field>();
+    private Map<String, List<Field>> fieldMap = new HashMap<String, List<Field>>();
+    
+    /**
+     * Creates a new empty <code>Header</code>.
+     */
+    public Header() {
+    }
+
+    /**
+     * Creates a new <code>Header</code> from the specified
+     * <code>Header</code>. The <code>Header</code> instance is initialized
+     * with a copy of the list of {@link Field}s of the specified
+     * <code>Header</code>. The <code>Field</code> objects are not copied
+     * because they are immutable and can safely be shared between headers.
+     * 
+     * @param other
+     *            header to copy.
+     */
+    public Header(Header other) {
+        for (Field otherField : other.fields) {
+            addField(otherField);
+        }
+    }
+
+    /**
+     * Creates a new <code>Header</code> from the specified stream.
+     * 
+     * @param is the stream to read the header from.
+     * 
+     * @throws IOException on I/O errors.
+     * @throws MimeIOException on MIME protocol violations.
+     */
+    public Header(InputStream is) 
+            throws IOException, MimeIOException {
+        final MimeStreamParser parser = new MimeStreamParser();
+        parser.setContentHandler(new AbstractContentHandler() {
+            @Override
+            public void endHeader() {
+                parser.stop();
+            }
+            @Override
+            public void field(Field field) throws MimeException {
+                addField(field);
+            }
+        });
+        try {
+            parser.parse(is);
+        } catch (MimeException ex) {
+            throw new MimeIOException(ex);
+        }
+    }
+
+    /**
+     * Adds a field to the end of the list of fields.
+     * 
+     * @param field the field to add.
+     */
+    public void addField(Field field) {
+        List<Field> values = fieldMap.get(field.getName().toLowerCase());
+        if (values == null) {
+            values = new LinkedList<Field>();
+            fieldMap.put(field.getName().toLowerCase(), values);
+        }
+        values.add(field);
+        fields.add(field);
+    }
+    
+    /**
+     * Gets the fields of this header. The returned list will not be
+     * modifiable.
+     * 
+     * @return the list of <code>Field</code> objects.
+     */
+    public List<Field> getFields() {
+        return Collections.unmodifiableList(fields);
+    }
+
+    /**
+     * Gets a <code>Field</code> given a field name. If there are multiple
+     * such fields defined in this header the first one will be returned.
+     * 
+     * @param name the field name (e.g. From, Subject).
+     * @return the field or <code>null</code> if none found.
+     */
+    public Field getField(String name) {
+        List<Field> l = fieldMap.get(name.toLowerCase());
+        if (l != null && !l.isEmpty()) {
+            return l.get(0);
+        }
+        return null;
+    }
+    
+    /**
+     * Gets all <code>Field</code>s having the specified field name. 
+     * 
+     * @param name the field name (e.g. From, Subject).
+     * @return the list of fields.
+     */
+    public List<Field> getFields(final String name) {
+        final String lowerCaseName = name.toLowerCase();
+        final List<Field> l = fieldMap.get(lowerCaseName);
+        final List<Field> results;
+        if (l == null || l.isEmpty()) {
+            results = Collections.emptyList();
+        } else {
+            results = Collections.unmodifiableList(l);
+        }
+        return results;
+    }
+
+    /**
+     * Returns an iterator over the list of fields of this header.
+     * 
+     * @return an iterator.
+     */
+    public Iterator<Field> iterator() {
+        return Collections.unmodifiableList(fields).iterator();
+    }
+
+    /**
+     * Removes all <code>Field</code>s having the specified field name.
+     * 
+     * @param name
+     *            the field name (e.g. From, Subject).
+     * @return number of fields removed.
+     */
+    public int removeFields(String name) {
+        final String lowerCaseName = name.toLowerCase();
+        List<Field> removed = fieldMap.remove(lowerCaseName);
+        if (removed == null || removed.isEmpty())
+            return 0;
+
+        for (Iterator<Field> iterator = fields.iterator(); iterator.hasNext();) {
+            Field field = iterator.next();
+            if (field.getName().equalsIgnoreCase(name))
+                iterator.remove();
+        }
+
+        return removed.size();
+    }
+
+    /**
+     * Sets or replaces a field. This method is useful for header fields such as
+     * Subject or Message-ID that should not occur more than once in a message.
+     * 
+     * If this <code>Header</code> does not already contain a header field of
+     * the same name as the given field then it is added to the end of the list
+     * of fields (same behavior as {@link #addField(Field)}). Otherwise the
+     * first occurrence of a field with the same name is replaced by the given
+     * field and all further occurrences are removed.
+     * 
+     * @param field the field to set.
+     */
+    public void setField(Field field) {
+        final String lowerCaseName = field.getName().toLowerCase();
+        List<Field> l = fieldMap.get(lowerCaseName);
+        if (l == null || l.isEmpty()) {
+            addField(field);
+            return;
+        }
+
+        l.clear();
+        l.add(field);
+
+        int firstOccurrence = -1;
+        int index = 0;
+        for (Iterator<Field> iterator = fields.iterator(); iterator.hasNext(); index++) {
+            Field f = iterator.next();
+            if (f.getName().equalsIgnoreCase(field.getName())) {
+                iterator.remove();
+
+                if (firstOccurrence == -1)
+                    firstOccurrence = index;
+            }
+        }
+
+        fields.add(firstOccurrence, field);
+    }
+
+    /**
+     * Return Header Object as String representation. Each headerline is
+     * seperated by "\r\n"
+     * 
+     * @return headers
+     */
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder(128);
+        for (Field field : fields) {
+            str.append(field.toString());
+            str.append("\r\n");
+        }
+        return str.toString();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Message.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Message.java
new file mode 100644
index 0000000..72d3f8c
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Message.java
@@ -0,0 +1,604 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.field.AddressListField;
+import org.apache.james.mime4j.field.DateTimeField;
+import org.apache.james.mime4j.field.FieldName;
+import org.apache.james.mime4j.field.Fields;
+import org.apache.james.mime4j.field.MailboxField;
+import org.apache.james.mime4j.field.MailboxListField;
+import org.apache.james.mime4j.field.UnstructuredField;
+import org.apache.james.mime4j.field.address.Address;
+import org.apache.james.mime4j.field.address.AddressList;
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.field.address.MailboxList;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.parser.MimeEntityConfig;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.storage.DefaultStorageProvider;
+import org.apache.james.mime4j.storage.StorageProvider;
+
+/**
+ * Represents a MIME message. The following code parses a stream into a
+ * <code>Message</code> object.
+ * 
+ * <pre>
+ * Message msg = new Message(new FileInputStream(&quot;mime.msg&quot;));
+ * </pre>
+ */
+public class Message extends Entity implements Body {
+
+    /**
+     * Creates a new empty <code>Message</code>.
+     */
+    public Message() {
+    }
+
+    /**
+     * Creates a new <code>Message</code> from the specified
+     * <code>Message</code>. The <code>Message</code> instance is
+     * initialized with copies of header and body of the specified
+     * <code>Message</code>. The parent entity of the new message is
+     * <code>null</code>.
+     * 
+     * @param other
+     *            message to copy.
+     * @throws UnsupportedOperationException
+     *             if <code>other</code> contains a {@link SingleBody} that
+     *             does not support the {@link SingleBody#copy() copy()}
+     *             operation.
+     * @throws IllegalArgumentException
+     *             if <code>other</code> contains a <code>Body</code> that
+     *             is neither a {@link Message}, {@link Multipart} or
+     *             {@link SingleBody}.
+     */
+    public Message(Message other) {
+        super(other);
+    }
+
+    /**
+     * Parses the specified MIME message stream into a <code>Message</code>
+     * instance.
+     * 
+     * @param is
+     *            the stream to parse.
+     * @throws IOException
+     *             on I/O errors.
+     * @throws MimeIOException
+     *             on MIME protocol violations.
+     */
+    public Message(InputStream is) throws IOException, MimeIOException {
+        this(is, null, DefaultStorageProvider.getInstance());
+    }
+
+    /**
+     * Parses the specified MIME message stream into a <code>Message</code>
+     * instance using given {@link MimeEntityConfig}.
+     * 
+     * @param is
+     *            the stream to parse.
+     * @throws IOException
+     *             on I/O errors.
+     * @throws MimeIOException
+     *             on MIME protocol violations.
+     */
+    public Message(InputStream is, MimeEntityConfig config) throws IOException,
+            MimeIOException {
+        this(is, config, DefaultStorageProvider.getInstance());
+    }
+
+    /**
+     * Parses the specified MIME message stream into a <code>Message</code>
+     * instance using given {@link MimeEntityConfig} and {@link StorageProvider}.
+     * 
+     * @param is
+     *            the stream to parse.
+     * @param config
+     *            {@link MimeEntityConfig} to use.
+     * @param storageProvider
+     *            {@link StorageProvider} to use for storing text and binary
+     *            message bodies.
+     * @throws IOException
+     *             on I/O errors.
+     * @throws MimeIOException
+     *             on MIME protocol violations.
+     */
+    public Message(InputStream is, MimeEntityConfig config,
+            StorageProvider storageProvider) throws IOException,
+            MimeIOException {
+        try {
+            MimeStreamParser parser = new MimeStreamParser(config);
+            parser.setContentHandler(new MessageBuilder(this, storageProvider));
+            parser.parse(is);
+        } catch (MimeException e) {
+            throw new MimeIOException(e);
+        }
+    }
+
+    /**
+     * Write the content to the given output stream using the
+     * {@link MessageWriter#DEFAULT default} message writer.
+     * 
+     * @param out
+     *            the output stream to write to.
+     * @throws IOException
+     *             in case of an I/O error
+     * @see MessageWriter
+     */
+    public void writeTo(OutputStream out) throws IOException {
+        MessageWriter.DEFAULT.writeEntity(this, out);
+    }
+
+    /**
+     * Returns the value of the <i>Message-ID</i> header field of this message
+     * or <code>null</code> if it is not present.
+     * 
+     * @return the identifier of this message.
+     */
+    public String getMessageId() {
+        Field field = obtainField(FieldName.MESSAGE_ID);
+        if (field == null)
+            return null;
+
+        return field.getBody();
+    }
+
+    /**
+     * Creates and sets a new <i>Message-ID</i> header field for this message.
+     * A <code>Header</code> is created if this message does not already have
+     * one.
+     * 
+     * @param hostname
+     *            host name to be included in the identifier or
+     *            <code>null</code> if no host name should be included.
+     */
+    public void createMessageId(String hostname) {
+        Header header = obtainHeader();
+
+        header.setField(Fields.messageId(hostname));
+    }
+
+    /**
+     * Returns the (decoded) value of the <i>Subject</i> header field of this
+     * message or <code>null</code> if it is not present.
+     * 
+     * @return the subject of this message.
+     */
+    public String getSubject() {
+        UnstructuredField field = obtainField(FieldName.SUBJECT);
+        if (field == null)
+            return null;
+
+        return field.getValue();
+    }
+
+    /**
+     * Sets the <i>Subject</i> header field for this message. The specified
+     * string may contain non-ASCII characters, in which case it gets encoded as
+     * an 'encoded-word' automatically. A <code>Header</code> is created if
+     * this message does not already have one.
+     * 
+     * @param subject
+     *            subject to set or <code>null</code> to remove the subject
+     *            header field.
+     */
+    public void setSubject(String subject) {
+        Header header = obtainHeader();
+
+        if (subject == null) {
+            header.removeFields(FieldName.SUBJECT);
+        } else {
+            header.setField(Fields.subject(subject));
+        }
+    }
+
+    /**
+     * Returns the value of the <i>Date</i> header field of this message as
+     * <code>Date</code> object or <code>null</code> if it is not present.
+     * 
+     * @return the date of this message.
+     */
+    public Date getDate() {
+        DateTimeField dateField = obtainField(FieldName.DATE);
+        if (dateField == null)
+            return null;
+
+        return dateField.getDate();
+    }
+
+    /**
+     * Sets the <i>Date</i> header field for this message. This method uses the
+     * default <code>TimeZone</code> of this host to encode the specified
+     * <code>Date</code> object into a string.
+     * 
+     * @param date
+     *            date to set or <code>null</code> to remove the date header
+     *            field.
+     */
+    public void setDate(Date date) {
+        setDate(date, null);
+    }
+
+    /**
+     * Sets the <i>Date</i> header field for this message. The specified
+     * <code>TimeZone</code> is used to encode the specified <code>Date</code>
+     * object into a string.
+     * 
+     * @param date
+     *            date to set or <code>null</code> to remove the date header
+     *            field.
+     * @param zone
+     *            a time zone.
+     */
+    public void setDate(Date date, TimeZone zone) {
+        Header header = obtainHeader();
+
+        if (date == null) {
+            header.removeFields(FieldName.DATE);
+        } else {
+            header.setField(Fields.date(FieldName.DATE, date, zone));
+        }
+    }
+
+    /**
+     * Returns the value of the <i>Sender</i> header field of this message as
+     * <code>Mailbox</code> object or <code>null</code> if it is not
+     * present.
+     * 
+     * @return the sender of this message.
+     */
+    public Mailbox getSender() {
+        return getMailbox(FieldName.SENDER);
+    }
+
+    /**
+     * Sets the <i>Sender</i> header field of this message to the specified
+     * mailbox address.
+     * 
+     * @param sender
+     *            address to set or <code>null</code> to remove the header
+     *            field.
+     */
+    public void setSender(Mailbox sender) {
+        setMailbox(FieldName.SENDER, sender);
+    }
+
+    /**
+     * Returns the value of the <i>From</i> header field of this message as
+     * <code>MailboxList</code> object or <code>null</code> if it is not
+     * present.
+     * 
+     * @return value of the from field of this message.
+     */
+    public MailboxList getFrom() {
+        return getMailboxList(FieldName.FROM);
+    }
+
+    /**
+     * Sets the <i>From</i> header field of this message to the specified
+     * mailbox address.
+     * 
+     * @param from
+     *            address to set or <code>null</code> to remove the header
+     *            field.
+     */
+    public void setFrom(Mailbox from) {
+        setMailboxList(FieldName.FROM, from);
+    }
+
+    /**
+     * Sets the <i>From</i> header field of this message to the specified
+     * mailbox addresses.
+     * 
+     * @param from
+     *            addresses to set or <code>null</code> or no arguments to
+     *            remove the header field.
+     */
+    public void setFrom(Mailbox... from) {
+        setMailboxList(FieldName.FROM, from);
+    }
+
+    /**
+     * Sets the <i>From</i> header field of this message to the specified
+     * mailbox addresses.
+     * 
+     * @param from
+     *            addresses to set or <code>null</code> or an empty collection
+     *            to remove the header field.
+     */
+    public void setFrom(Collection<Mailbox> from) {
+        setMailboxList(FieldName.FROM, from);
+    }
+
+    /**
+     * Returns the value of the <i>To</i> header field of this message as
+     * <code>AddressList</code> object or <code>null</code> if it is not
+     * present.
+     * 
+     * @return value of the to field of this message.
+     */
+    public AddressList getTo() {
+        return getAddressList(FieldName.TO);
+    }
+
+    /**
+     * Sets the <i>To</i> header field of this message to the specified
+     * address.
+     * 
+     * @param to
+     *            address to set or <code>null</code> to remove the header
+     *            field.
+     */
+    public void setTo(Address to) {
+        setAddressList(FieldName.TO, to);
+    }
+
+    /**
+     * Sets the <i>To</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param to
+     *            addresses to set or <code>null</code> or no arguments to
+     *            remove the header field.
+     */
+    public void setTo(Address... to) {
+        setAddressList(FieldName.TO, to);
+    }
+
+    /**
+     * Sets the <i>To</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param to
+     *            addresses to set or <code>null</code> or an empty collection
+     *            to remove the header field.
+     */
+    public void setTo(Collection<Address> to) {
+        setAddressList(FieldName.TO, to);
+    }
+
+    /**
+     * Returns the value of the <i>Cc</i> header field of this message as
+     * <code>AddressList</code> object or <code>null</code> if it is not
+     * present.
+     * 
+     * @return value of the cc field of this message.
+     */
+    public AddressList getCc() {
+        return getAddressList(FieldName.CC);
+    }
+
+    /**
+     * Sets the <i>Cc</i> header field of this message to the specified
+     * address.
+     * 
+     * @param cc
+     *            address to set or <code>null</code> to remove the header
+     *            field.
+     */
+    public void setCc(Address cc) {
+        setAddressList(FieldName.CC, cc);
+    }
+
+    /**
+     * Sets the <i>Cc</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param cc
+     *            addresses to set or <code>null</code> or no arguments to
+     *            remove the header field.
+     */
+    public void setCc(Address... cc) {
+        setAddressList(FieldName.CC, cc);
+    }
+
+    /**
+     * Sets the <i>Cc</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param cc
+     *            addresses to set or <code>null</code> or an empty collection
+     *            to remove the header field.
+     */
+    public void setCc(Collection<Address> cc) {
+        setAddressList(FieldName.CC, cc);
+    }
+
+    /**
+     * Returns the value of the <i>Bcc</i> header field of this message as
+     * <code>AddressList</code> object or <code>null</code> if it is not
+     * present.
+     * 
+     * @return value of the bcc field of this message.
+     */
+    public AddressList getBcc() {
+        return getAddressList(FieldName.BCC);
+    }
+
+    /**
+     * Sets the <i>Bcc</i> header field of this message to the specified
+     * address.
+     * 
+     * @param bcc
+     *            address to set or <code>null</code> to remove the header
+     *            field.
+     */
+    public void setBcc(Address bcc) {
+        setAddressList(FieldName.BCC, bcc);
+    }
+
+    /**
+     * Sets the <i>Bcc</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param bcc
+     *            addresses to set or <code>null</code> or no arguments to
+     *            remove the header field.
+     */
+    public void setBcc(Address... bcc) {
+        setAddressList(FieldName.BCC, bcc);
+    }
+
+    /**
+     * Sets the <i>Bcc</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param bcc
+     *            addresses to set or <code>null</code> or an empty collection
+     *            to remove the header field.
+     */
+    public void setBcc(Collection<Address> bcc) {
+        setAddressList(FieldName.BCC, bcc);
+    }
+
+    /**
+     * Returns the value of the <i>Reply-To</i> header field of this message as
+     * <code>AddressList</code> object or <code>null</code> if it is not
+     * present.
+     * 
+     * @return value of the reply to field of this message.
+     */
+    public AddressList getReplyTo() {
+        return getAddressList(FieldName.REPLY_TO);
+    }
+
+    /**
+     * Sets the <i>Reply-To</i> header field of this message to the specified
+     * address.
+     * 
+     * @param replyTo
+     *            address to set or <code>null</code> to remove the header
+     *            field.
+     */
+    public void setReplyTo(Address replyTo) {
+        setAddressList(FieldName.REPLY_TO, replyTo);
+    }
+
+    /**
+     * Sets the <i>Reply-To</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param replyTo
+     *            addresses to set or <code>null</code> or no arguments to
+     *            remove the header field.
+     */
+    public void setReplyTo(Address... replyTo) {
+        setAddressList(FieldName.REPLY_TO, replyTo);
+    }
+
+    /**
+     * Sets the <i>Reply-To</i> header field of this message to the specified
+     * addresses.
+     * 
+     * @param replyTo
+     *            addresses to set or <code>null</code> or an empty collection
+     *            to remove the header field.
+     */
+    public void setReplyTo(Collection<Address> replyTo) {
+        setAddressList(FieldName.REPLY_TO, replyTo);
+    }
+
+    private Mailbox getMailbox(String fieldName) {
+        MailboxField field = obtainField(fieldName);
+        if (field == null)
+            return null;
+
+        return field.getMailbox();
+    }
+
+    private void setMailbox(String fieldName, Mailbox mailbox) {
+        Header header = obtainHeader();
+
+        if (mailbox == null) {
+            header.removeFields(fieldName);
+        } else {
+            header.setField(Fields.mailbox(fieldName, mailbox));
+        }
+    }
+
+    private MailboxList getMailboxList(String fieldName) {
+        MailboxListField field = obtainField(fieldName);
+        if (field == null)
+            return null;
+
+        return field.getMailboxList();
+    }
+
+    private void setMailboxList(String fieldName, Mailbox mailbox) {
+        setMailboxList(fieldName, mailbox == null ? null : Collections
+                .singleton(mailbox));
+    }
+
+    private void setMailboxList(String fieldName, Mailbox... mailboxes) {
+        setMailboxList(fieldName, mailboxes == null ? null : Arrays
+                .asList(mailboxes));
+    }
+
+    private void setMailboxList(String fieldName, Collection<Mailbox> mailboxes) {
+        Header header = obtainHeader();
+
+        if (mailboxes == null || mailboxes.isEmpty()) {
+            header.removeFields(fieldName);
+        } else {
+            header.setField(Fields.mailboxList(fieldName, mailboxes));
+        }
+    }
+
+    private AddressList getAddressList(String fieldName) {
+        AddressListField field = obtainField(fieldName);
+        if (field == null)
+            return null;
+
+        return field.getAddressList();
+    }
+
+    private void setAddressList(String fieldName, Address address) {
+        setAddressList(fieldName, address == null ? null : Collections
+                .singleton(address));
+    }
+
+    private void setAddressList(String fieldName, Address... addresses) {
+        setAddressList(fieldName, addresses == null ? null : Arrays
+                .asList(addresses));
+    }
+
+    private void setAddressList(String fieldName, Collection<Address> addresses) {
+        Header header = obtainHeader();
+
+        if (addresses == null || addresses.isEmpty()) {
+            header.removeFields(fieldName);
+        } else {
+            header.setField(Fields.addressList(fieldName, addresses));
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java
new file mode 100644
index 0000000..8d1f573
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/MessageBuilder.java
@@ -0,0 +1,220 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Stack;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.Base64InputStream;
+import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.field.AbstractField;
+import org.apache.james.mime4j.parser.ContentHandler;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.storage.StorageProvider;
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * A <code>ContentHandler</code> for building an <code>Entity</code> to be
+ * used in conjunction with a {@link MimeStreamParser}.
+ */
+public class MessageBuilder implements ContentHandler {
+
+    private final Entity entity;
+    private final BodyFactory bodyFactory;
+    private Stack<Object> stack = new Stack<Object>();
+    
+    public MessageBuilder(Entity entity) {
+        this.entity = entity;
+        this.bodyFactory = new BodyFactory();
+    }
+    
+    public MessageBuilder(Entity entity, StorageProvider storageProvider) {
+        this.entity = entity;
+        this.bodyFactory = new BodyFactory(storageProvider);
+    }
+    
+    private void expect(Class<?> c) {
+        if (!c.isInstance(stack.peek())) {
+            throw new IllegalStateException("Internal stack error: "
+                    + "Expected '" + c.getName() + "' found '"
+                    + stack.peek().getClass().getName() + "'");
+        }
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#startMessage()
+     */
+    public void startMessage() throws MimeException {
+        if (stack.isEmpty()) {
+            stack.push(this.entity);
+        } else {
+            expect(Entity.class);
+            Message m = new Message();
+            ((Entity) stack.peek()).setBody(m);
+            stack.push(m);
+        }
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#endMessage()
+     */
+    public void endMessage() throws MimeException {
+        expect(Message.class);
+        stack.pop();
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#startHeader()
+     */
+    public void startHeader() throws MimeException {
+        stack.push(new Header());
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#field(Field)
+     */
+    public void field(Field field) throws MimeException {
+        expect(Header.class);
+        Field parsedField = AbstractField.parse(field.getRaw()); 
+        ((Header) stack.peek()).addField(parsedField);
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#endHeader()
+     */
+    public void endHeader() throws MimeException {
+        expect(Header.class);
+        Header h = (Header) stack.pop();
+        expect(Entity.class);
+        ((Entity) stack.peek()).setHeader(h);
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#startMultipart(org.apache.james.mime4j.descriptor.BodyDescriptor)
+     */
+    public void startMultipart(final BodyDescriptor bd) throws MimeException {
+        expect(Entity.class);
+        
+        final Entity e = (Entity) stack.peek();
+        final String subType = bd.getSubType();
+        final Multipart multiPart = new Multipart(subType);
+        e.setBody(multiPart);
+        stack.push(multiPart);
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#body(org.apache.james.mime4j.descriptor.BodyDescriptor, java.io.InputStream)
+     */
+    public void body(BodyDescriptor bd, final InputStream is) throws MimeException, IOException {
+        expect(Entity.class);
+        
+        final String enc = bd.getTransferEncoding();
+        
+        final Body body;
+        
+        final InputStream decodedStream;
+        if (MimeUtil.ENC_BASE64.equals(enc)) {
+            decodedStream = new Base64InputStream(is);
+        } else if (MimeUtil.ENC_QUOTED_PRINTABLE.equals(enc)) {
+            decodedStream = new QuotedPrintableInputStream(is);
+        } else {
+            decodedStream = is;
+        }
+        
+        if (bd.getMimeType().startsWith("text/")) {
+            body = bodyFactory.textBody(decodedStream, bd.getCharset());
+        } else {
+            body = bodyFactory.binaryBody(decodedStream);
+        }
+        
+        Entity entity = ((Entity) stack.peek());
+        entity.setBody(body);
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#endMultipart()
+     */
+    public void endMultipart() throws MimeException {
+        stack.pop();
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#startBodyPart()
+     */
+    public void startBodyPart() throws MimeException {
+        expect(Multipart.class);
+        
+        BodyPart bodyPart = new BodyPart();
+        ((Multipart) stack.peek()).addBodyPart(bodyPart);
+        stack.push(bodyPart);
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#endBodyPart()
+     */
+    public void endBodyPart() throws MimeException {
+        expect(BodyPart.class);
+        stack.pop();
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#epilogue(java.io.InputStream)
+     */
+    public void epilogue(InputStream is) throws MimeException, IOException {
+        expect(Multipart.class);
+        ByteSequence bytes = loadStream(is);
+        ((Multipart) stack.peek()).setEpilogueRaw(bytes);
+    }
+    
+    /**
+     * @see org.apache.james.mime4j.parser.ContentHandler#preamble(java.io.InputStream)
+     */
+    public void preamble(InputStream is) throws MimeException, IOException {
+        expect(Multipart.class);
+        ByteSequence bytes = loadStream(is);
+        ((Multipart) stack.peek()).setPreambleRaw(bytes);
+    }
+    
+    /**
+     * Unsupported.
+     * @see org.apache.james.mime4j.parser.ContentHandler#raw(java.io.InputStream)
+     */
+    public void raw(InputStream is) throws MimeException, IOException {
+        throw new UnsupportedOperationException("Not supported");
+    }
+
+    private static ByteSequence loadStream(InputStream in) throws IOException {
+        ByteArrayBuffer bab = new ByteArrayBuffer(64);
+
+        int b;
+        while ((b = in.read()) != -1) {
+            bab.append(b);
+        }
+
+        return bab;
+    }
+
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/MessageWriter.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/MessageWriter.java
new file mode 100644
index 0000000..454e3f1
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/MessageWriter.java
@@ -0,0 +1,221 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.FieldName;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * Writes a message (or a part of a message) to an output stream.
+ * <p>
+ * This class cannot be instantiated; instead the static instance
+ * {@link #DEFAULT} implements the default strategy for writing a message.
+ * <p>
+ * This class may be subclassed to implement custom strategies for writing
+ * messages.
+ */
+public class MessageWriter {
+
+    private static final byte[] CRLF = { '\r', '\n' };
+    private static final byte[] DASHES = { '-', '-' };
+
+    /**
+     * The default message writer.
+     */
+    public static final MessageWriter DEFAULT = new MessageWriter();
+
+    /**
+     * Protected constructor prevents direct instantiation.
+     */
+    protected MessageWriter() {
+    }
+
+    /**
+     * Write the specified <code>Body</code> to the specified
+     * <code>OutputStream</code>.
+     * 
+     * @param body
+     *            the <code>Body</code> to write.
+     * @param out
+     *            the OutputStream to write to.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public void writeBody(Body body, OutputStream out) throws IOException {
+        if (body instanceof Message) {
+            writeEntity((Message) body, out);
+        } else if (body instanceof Multipart) {
+            writeMultipart((Multipart) body, out);
+        } else if (body instanceof SingleBody) {
+            ((SingleBody) body).writeTo(out);
+        } else
+            throw new IllegalArgumentException("Unsupported body class");
+    }
+
+    /**
+     * Write the specified <code>Entity</code> to the specified
+     * <code>OutputStream</code>.
+     * 
+     * @param entity
+     *            the <code>Entity</code> to write.
+     * @param out
+     *            the OutputStream to write to.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public void writeEntity(Entity entity, OutputStream out) throws IOException {
+        final Header header = entity.getHeader();
+        if (header == null)
+            throw new IllegalArgumentException("Missing header");
+
+        writeHeader(header, out);
+
+        final Body body = entity.getBody();
+        if (body == null)
+            throw new IllegalArgumentException("Missing body");
+
+        boolean binaryBody = body instanceof BinaryBody;
+        OutputStream encOut = encodeStream(out, entity
+                .getContentTransferEncoding(), binaryBody);
+
+        writeBody(body, encOut);
+
+        // close if wrapped (base64 or quoted-printable)
+        if (encOut != out)
+            encOut.close();
+    }
+
+    /**
+     * Write the specified <code>Multipart</code> to the specified
+     * <code>OutputStream</code>.
+     * 
+     * @param multipart
+     *            the <code>Multipart</code> to write.
+     * @param out
+     *            the OutputStream to write to.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public void writeMultipart(Multipart multipart, OutputStream out)
+            throws IOException {
+        ContentTypeField contentType = getContentType(multipart);
+
+        ByteSequence boundary = getBoundary(contentType);
+
+        writeBytes(multipart.getPreambleRaw(), out);
+        out.write(CRLF);
+
+        for (BodyPart bodyPart : multipart.getBodyParts()) {
+            out.write(DASHES);
+            writeBytes(boundary, out);
+            out.write(CRLF);
+
+            writeEntity(bodyPart, out);
+            out.write(CRLF);
+        }
+
+        out.write(DASHES);
+        writeBytes(boundary, out);
+        out.write(DASHES);
+        out.write(CRLF);
+
+        writeBytes(multipart.getEpilogueRaw(), out);
+    }
+
+    /**
+     * Write the specified <code>Header</code> to the specified
+     * <code>OutputStream</code>.
+     * 
+     * @param header
+     *            the <code>Header</code> to write.
+     * @param out
+     *            the OutputStream to write to.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public void writeHeader(Header header, OutputStream out) throws IOException {
+        for (Field field : header) {
+            writeBytes(field.getRaw(), out);
+            out.write(CRLF);
+        }
+
+        out.write(CRLF);
+    }
+
+    protected OutputStream encodeStream(OutputStream out, String encoding,
+            boolean binaryBody) throws IOException {
+        if (MimeUtil.isBase64Encoding(encoding)) {
+            return CodecUtil.wrapBase64(out);
+        } else if (MimeUtil.isQuotedPrintableEncoded(encoding)) {
+            return CodecUtil.wrapQuotedPrintable(out, binaryBody);
+        } else {
+            return out;
+        }
+    }
+
+    private ContentTypeField getContentType(Multipart multipart) {
+        Entity parent = multipart.getParent();
+        if (parent == null)
+            throw new IllegalArgumentException(
+                    "Missing parent entity in multipart");
+
+        Header header = parent.getHeader();
+        if (header == null)
+            throw new IllegalArgumentException(
+                    "Missing header in parent entity");
+
+        ContentTypeField contentType = (ContentTypeField) header
+                .getField(FieldName.CONTENT_TYPE);
+        if (contentType == null)
+            throw new IllegalArgumentException(
+                    "Content-Type field not specified");
+
+        return contentType;
+    }
+
+    private ByteSequence getBoundary(ContentTypeField contentType) {
+        String boundary = contentType.getBoundary();
+        if (boundary == null)
+            throw new IllegalArgumentException(
+                    "Multipart boundary not specified");
+
+        return ContentUtil.encode(boundary);
+    }
+
+    private void writeBytes(ByteSequence byteSequence, OutputStream out)
+            throws IOException {
+        if (byteSequence instanceof ByteArrayBuffer) {
+            ByteArrayBuffer bab = (ByteArrayBuffer) byteSequence;
+            out.write(bab.buffer(), 0, bab.length());
+        } else {
+            out.write(byteSequence.toByteArray());
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Multipart.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Multipart.java
new file mode 100644
index 0000000..90aec15
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/Multipart.java
@@ -0,0 +1,319 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+
+/**
+ * Represents a MIME multipart body (see RFC 2045).A multipart body has a
+ * ordered list of body parts. The multipart body also has a preamble and
+ * epilogue. The preamble consists of whatever characters appear before the
+ * first body part while the epilogue consists of whatever characters come after
+ * the last body part.
+ */
+public class Multipart implements Body {
+
+    private List<BodyPart> bodyParts = new LinkedList<BodyPart>();
+    private Entity parent = null;
+
+    private ByteSequence preamble;
+    private transient String preambleStrCache;
+    private ByteSequence epilogue;
+    private transient String epilogueStrCache;
+
+    private String subType;
+
+    /**
+     * Creates a new empty <code>Multipart</code> instance.
+     */
+    public Multipart(String subType) {
+        preamble = ByteSequence.EMPTY;
+        preambleStrCache = "";
+        epilogue = ByteSequence.EMPTY;
+        epilogueStrCache = "";
+
+        this.subType = subType;
+    }
+
+    /**
+     * Creates a new <code>Multipart</code> from the specified
+     * <code>Multipart</code>. The <code>Multipart</code> instance is
+     * initialized with copies of preamble, epilogue, sub type and the list of
+     * body parts of the specified <code>Multipart</code>. The parent entity
+     * of the new multipart is <code>null</code>.
+     * 
+     * @param other
+     *            multipart to copy.
+     * @throws UnsupportedOperationException
+     *             if <code>other</code> contains a {@link SingleBody} that
+     *             does not support the {@link SingleBody#copy() copy()}
+     *             operation.
+     * @throws IllegalArgumentException
+     *             if <code>other</code> contains a <code>Body</code> that
+     *             is neither a {@link Message}, {@link Multipart} or
+     *             {@link SingleBody}.
+     */
+    public Multipart(Multipart other) {
+        preamble = other.preamble;
+        preambleStrCache = other.preambleStrCache;
+        epilogue = other.epilogue;
+        epilogueStrCache = other.epilogueStrCache;
+
+        for (BodyPart otherBodyPart : other.bodyParts) {
+            BodyPart bodyPartCopy = new BodyPart(otherBodyPart);
+            addBodyPart(bodyPartCopy);
+        }
+
+        subType = other.subType;
+    }
+
+    /**
+     * Gets the multipart sub-type. E.g. <code>alternative</code> (the
+     * default) or <code>parallel</code>. See RFC 2045 for common sub-types
+     * and their meaning.
+     * 
+     * @return the multipart sub-type.
+     */
+    public String getSubType() {
+        return subType;
+    }
+
+    /**
+     * Sets the multipart sub-type. E.g. <code>alternative</code> or
+     * <code>parallel</code>. See RFC 2045 for common sub-types and their
+     * meaning.
+     * 
+     * @param subType
+     *            the sub-type.
+     */
+    public void setSubType(String subType) {
+        this.subType = subType;
+    }
+
+    /**
+     * @see org.apache.james.mime4j.message.Body#getParent()
+     */
+    public Entity getParent() {
+        return parent;
+    }
+
+    /**
+     * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
+     */
+    public void setParent(Entity parent) {
+        this.parent = parent;
+        for (BodyPart bodyPart : bodyParts) {
+            bodyPart.setParent(parent);
+        }
+    }
+
+    /**
+     * Returns the number of body parts.
+     * 
+     * @return number of <code>BodyPart</code> objects.
+     */
+    public int getCount() {
+        return bodyParts.size();
+    }
+
+    /**
+     * Gets the list of body parts. The list is immutable.
+     * 
+     * @return the list of <code>BodyPart</code> objects.
+     */
+    public List<BodyPart> getBodyParts() {
+        return Collections.unmodifiableList(bodyParts);
+    }
+
+    /**
+     * Sets the list of body parts.
+     * 
+     * @param bodyParts
+     *            the new list of <code>BodyPart</code> objects.
+     */
+    public void setBodyParts(List<BodyPart> bodyParts) {
+        this.bodyParts = bodyParts;
+        for (BodyPart bodyPart : bodyParts) {
+            bodyPart.setParent(parent);
+        }
+    }
+
+    /**
+     * Adds a body part to the end of the list of body parts.
+     * 
+     * @param bodyPart
+     *            the body part.
+     */
+    public void addBodyPart(BodyPart bodyPart) {
+        if (bodyPart == null)
+            throw new IllegalArgumentException();
+
+        bodyParts.add(bodyPart);
+        bodyPart.setParent(parent);
+    }
+
+    /**
+     * Inserts a body part at the specified position in the list of body parts.
+     * 
+     * @param bodyPart
+     *            the body part.
+     * @param index
+     *            index at which the specified body part is to be inserted.
+     * @throws IndexOutOfBoundsException
+     *             if the index is out of range (index &lt; 0 || index &gt;
+     *             getCount()).
+     */
+    public void addBodyPart(BodyPart bodyPart, int index) {
+        if (bodyPart == null)
+            throw new IllegalArgumentException();
+
+        bodyParts.add(index, bodyPart);
+        bodyPart.setParent(parent);
+    }
+
+    /**
+     * Removes the body part at the specified position in the list of body
+     * parts.
+     * 
+     * @param index
+     *            index of the body part to be removed.
+     * @return the removed body part.
+     * @throws IndexOutOfBoundsException
+     *             if the index is out of range (index &lt; 0 || index &gt;=
+     *             getCount()).
+     */
+    public BodyPart removeBodyPart(int index) {
+        BodyPart bodyPart = bodyParts.remove(index);
+        bodyPart.setParent(null);
+        return bodyPart;
+    }
+
+    /**
+     * Replaces the body part at the specified position in the list of body
+     * parts with the specified body part.
+     * 
+     * @param bodyPart
+     *            body part to be stored at the specified position.
+     * @param index
+     *            index of body part to replace.
+     * @return the replaced body part.
+     * @throws IndexOutOfBoundsException
+     *             if the index is out of range (index &lt; 0 || index &gt;=
+     *             getCount()).
+     */
+    public BodyPart replaceBodyPart(BodyPart bodyPart, int index) {
+        if (bodyPart == null)
+            throw new IllegalArgumentException();
+
+        BodyPart replacedBodyPart = bodyParts.set(index, bodyPart);
+        if (bodyPart == replacedBodyPart)
+            throw new IllegalArgumentException(
+                    "Cannot replace body part with itself");
+
+        bodyPart.setParent(parent);
+        replacedBodyPart.setParent(null);
+
+        return replacedBodyPart;
+    }
+
+    // package private for now; might become public someday
+    ByteSequence getPreambleRaw() {
+        return preamble;
+    }
+
+    void setPreambleRaw(ByteSequence preamble) {
+        this.preamble = preamble;
+        this.preambleStrCache = null;
+    }
+
+    /**
+     * Gets the preamble.
+     * 
+     * @return the preamble.
+     */
+    public String getPreamble() {
+        if (preambleStrCache == null) {
+            preambleStrCache = ContentUtil.decode(preamble);
+        }
+        return preambleStrCache;
+    }
+
+    /**
+     * Sets the preamble.
+     * 
+     * @param preamble
+     *            the preamble.
+     */
+    public void setPreamble(String preamble) {
+        this.preamble = ContentUtil.encode(preamble);
+        this.preambleStrCache = preamble;
+    }
+
+    // package private for now; might become public someday
+    ByteSequence getEpilogueRaw() {
+        return epilogue;
+    }
+
+    void setEpilogueRaw(ByteSequence epilogue) {
+        this.epilogue = epilogue;
+        this.epilogueStrCache = null;
+    }
+
+    /**
+     * Gets the epilogue.
+     * 
+     * @return the epilogue.
+     */
+    public String getEpilogue() {
+        if (epilogueStrCache == null) {
+            epilogueStrCache = ContentUtil.decode(epilogue);
+        }
+        return epilogueStrCache;
+    }
+
+    /**
+     * Sets the epilogue.
+     * 
+     * @param epilogue
+     *            the epilogue.
+     */
+    public void setEpilogue(String epilogue) {
+        this.epilogue = ContentUtil.encode(epilogue);
+        this.epilogueStrCache = epilogue;
+    }
+
+    /**
+     * Disposes of the BodyParts of this Multipart. Note that the dispose call
+     * does not get forwarded to the parent entity of this Multipart.
+     * 
+     * @see org.apache.james.mime4j.message.Disposable#dispose()
+     */
+    public void dispose() {
+        for (BodyPart bodyPart : bodyParts) {
+            bodyPart.dispose();
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/SimpleContentHandler.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/SimpleContentHandler.java
new file mode 100644
index 0000000..c30c62a
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/SimpleContentHandler.java
@@ -0,0 +1,109 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.message;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.codec.Base64InputStream;

+import org.apache.james.mime4j.codec.QuotedPrintableInputStream;

+import org.apache.james.mime4j.descriptor.BodyDescriptor;

+import org.apache.james.mime4j.field.AbstractField;

+import org.apache.james.mime4j.parser.AbstractContentHandler;

+import org.apache.james.mime4j.parser.Field;

+import org.apache.james.mime4j.util.MimeUtil;

+

+import java.io.InputStream;

+import java.io.IOException;

+

+/**

+ * Abstract implementation of ContentHandler that automates common

+ * tasks. Currently performs header parsing and applies content-transfer

+ * decoding to body parts.

+ *

+ * 

+ */

+public abstract class SimpleContentHandler extends  AbstractContentHandler {

+

+    /**

+     * Called after headers are parsed.

+     */

+    public abstract void headers(Header header);

+

+    /**

+     * Called when the body of a discrete (non-multipart) entity is encountered.

+

+     * @param bd encapsulates the values (either read from the

+     *        message stream or, if not present, determined implictly

+     *        as described in the

+     *        MIME rfc:s) of the <code>Content-Type</code> and

+     *        <code>Content-Transfer-Encoding</code> header fields.

+     * @param is the contents of the body. Base64 or quoted-printable

+     *        decoding will be applied transparently.

+     * @throws IOException should be thrown on I/O errors.

+     */

+    public abstract void bodyDecoded(BodyDescriptor bd, InputStream is) throws IOException;

+

+

+    /* Implement introduced callbacks. */

+

+    private Header currHeader;

+

+    /**

+     * @see org.apache.james.mime4j.parser.AbstractContentHandler#startHeader()

+     */

+    @Override

+    public final void startHeader() {

+        currHeader = new Header();

+    }

+

+    /**

+     * @see org.apache.james.mime4j.parser.AbstractContentHandler#field(Field)

+     */

+    @Override

+    public final void field(Field field) throws MimeException {

+        Field parsedField = AbstractField.parse(field.getRaw()); 

+        currHeader.addField(parsedField);

+    }

+

+    /**

+     * @see org.apache.james.mime4j.parser.AbstractContentHandler#endHeader()

+     */

+    @Override

+    public final void endHeader() {

+        Header tmp = currHeader;

+        currHeader = null;

+        headers(tmp);

+    }

+

+    /**

+     * @see org.apache.james.mime4j.parser.AbstractContentHandler#body(org.apache.james.mime4j.descriptor.BodyDescriptor, java.io.InputStream)

+     */

+    @Override

+    public final void body(BodyDescriptor bd, InputStream is) throws IOException {

+        if (MimeUtil.isBase64Encoding(bd.getTransferEncoding())) {

+            bodyDecoded(bd, new Base64InputStream(is));

+        }

+        else if (MimeUtil.isQuotedPrintableEncoded(bd.getTransferEncoding())) {

+            bodyDecoded(bd, new QuotedPrintableInputStream(is));

+        }

+        else {

+            bodyDecoded(bd, is);

+        }

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/SingleBody.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/SingleBody.java
new file mode 100644
index 0000000..3a733df
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/SingleBody.java
@@ -0,0 +1,104 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Abstract implementation of a single message body; that is, a body that does
+ * not contain (directly or indirectly) any other child bodies. It also provides
+ * the parent functionality required by bodies.
+ */
+public abstract class SingleBody implements Body {
+
+    private Entity parent = null;
+
+    /**
+     * Sole constructor.
+     */
+    protected SingleBody() {
+    }
+
+    /**
+     * @see org.apache.james.mime4j.message.Body#getParent()
+     */
+    public Entity getParent() {
+        return parent;
+    }
+
+    /**
+     * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
+     */
+    public void setParent(Entity parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Writes this single body to the given stream.
+     * 
+     * @param out
+     *            the stream to write to.
+     * @throws IOException
+     *             in case of an I/O error
+     */
+    public abstract void writeTo(OutputStream out) throws IOException;
+
+    /**
+     * Returns a copy of this <code>SingleBody</code> (optional operation).
+     * <p>
+     * The general contract of this method is as follows:
+     * <ul>
+     * <li>Invoking {@link #getParent()} on the copy returns <code>null</code>.
+     * That means that the copy is detached from the parent entity of this
+     * <code>SingleBody</code>. The copy may get attached to a different
+     * entity later on.</li>
+     * <li>The underlying content does not have to be copied. Instead it may be
+     * shared between multiple copies of a <code>SingleBody</code>.</li>
+     * <li>If the underlying content is shared by multiple copies the
+     * implementation has to make sure that the content gets deleted when the
+     * last copy gets disposed of (and not before that).</li>
+     * </ul>
+     * <p>
+     * This implementation always throws an
+     * <code>UnsupportedOperationException</code>.
+     * 
+     * @return a copy of this <code>SingleBody</code>.
+     * @throws UnsupportedOperationException
+     *             if the <code>copy</code> operation is not supported by this
+     *             single body.
+     */
+    public SingleBody copy() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Subclasses should override this method if they have allocated resources
+     * that need to be freed explicitly (e.g. cannot be simply reclaimed by the
+     * garbage collector).
+     * 
+     * The default implementation of this method does nothing.
+     * 
+     * @see org.apache.james.mime4j.message.Disposable#dispose()
+     */
+    public void dispose() {
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
new file mode 100644
index 0000000..046585b
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
@@ -0,0 +1,75 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+import org.apache.james.mime4j.storage.MultiReferenceStorage;
+
+/**
+ * Binary body backed by a
+ * {@link org.apache.james.mime4j.storage.Storage}
+ */
+class StorageBinaryBody extends BinaryBody {
+
+    private MultiReferenceStorage storage;
+
+    public StorageBinaryBody(final MultiReferenceStorage storage) {
+        this.storage = storage;
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return storage.getInputStream();
+    }
+
+    @Override
+    public void writeTo(OutputStream out) throws IOException {
+        if (out == null)
+            throw new IllegalArgumentException();
+
+        InputStream in = storage.getInputStream();
+        CodecUtil.copy(in, out);
+        in.close();
+    }
+
+    @Override
+    public StorageBinaryBody copy() {
+        storage.addReference();
+        return new StorageBinaryBody(storage);
+    }
+
+    /**
+     * Deletes the Storage that holds the content of this binary body.
+     *
+     * @see org.apache.james.mime4j.message.Disposable#dispose()
+     */
+    @Override
+    public void dispose() {
+        if (storage != null) {
+            storage.delete();
+            storage = null;
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
new file mode 100644
index 0000000..6a58c08
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.nio.charset.Charset;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+import org.apache.james.mime4j.storage.MultiReferenceStorage;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Text body backed by a {@link org.apache.james.mime4j.storage.Storage}.
+ */
+class StorageTextBody extends TextBody {
+
+    private MultiReferenceStorage storage;
+    private Charset charset;
+
+    public StorageTextBody(MultiReferenceStorage storage, Charset charset) {
+        this.storage = storage;
+        this.charset = charset;
+    }
+
+    @Override
+    public String getMimeCharset() {
+        return CharsetUtil.toMimeCharset(charset.name());
+    }
+
+    @Override
+    public Reader getReader() throws IOException {
+        return new InputStreamReader(storage.getInputStream(), charset);
+    }
+
+    @Override
+    public void writeTo(OutputStream out) throws IOException {
+        if (out == null)
+            throw new IllegalArgumentException();
+
+        InputStream in = storage.getInputStream();
+        CodecUtil.copy(in, out);
+        in.close();
+    }
+
+    @Override
+    public StorageTextBody copy() {
+        storage.addReference();
+        return new StorageTextBody(storage, charset);
+    }
+
+    /**
+     * Deletes the Storage that holds the content of this text body.
+     *
+     * @see org.apache.james.mime4j.message.Disposable#dispose()
+     */
+    @Override
+    public void dispose() {
+        if (storage != null) {
+            storage.delete();
+            storage = null;
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StringTextBody.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
new file mode 100644
index 0000000..4acd01e
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
@@ -0,0 +1,81 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Text body backed by a <code>String</code>.
+ */
+class StringTextBody extends TextBody {
+
+    private final String text;
+    private final Charset charset;
+
+    public StringTextBody(final String text, Charset charset) {
+        this.text = text;
+        this.charset = charset;
+    }
+
+    @Override
+    public String getMimeCharset() {
+        return CharsetUtil.toMimeCharset(charset.name());
+    }
+
+    @Override
+    public Reader getReader() throws IOException {
+        return new StringReader(text);
+    }
+
+    @Override
+    public void writeTo(OutputStream out) throws IOException {
+        if (out == null)
+            throw new IllegalArgumentException();
+
+        Reader reader = new StringReader(text);
+        Writer writer = new OutputStreamWriter(out, charset);
+
+        char buffer[] = new char[1024];
+        while (true) {
+            int nChars = reader.read(buffer);
+            if (nChars == -1)
+                break;
+
+            writer.write(buffer, 0, nChars);
+        }
+
+        reader.close();
+        writer.flush();
+    }
+
+    @Override
+    public StringTextBody copy() {
+        return new StringTextBody(text, charset);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/TextBody.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/TextBody.java
new file mode 100644
index 0000000..d6669f4
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/message/TextBody.java
@@ -0,0 +1,53 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.message;

+

+import java.io.IOException;

+import java.io.Reader;

+

+/**

+ * Encapsulates the contents of a <code>text/*</code> entity body.

+ */

+public abstract class TextBody extends SingleBody {

+

+    /**

+     * Sole constructor.

+     */

+    protected TextBody() {

+    }

+

+    /**

+     * Returns the MIME charset of this text body.

+     * 

+     * @return the MIME charset.

+     */

+    public abstract String getMimeCharset();

+

+    /**

+     * Gets a <code>Reader</code> which may be used to read out the contents

+     * of this body.

+     * 

+     * @return the <code>Reader</code>.

+     * @throws IOException

+     *             on I/O errors.

+     */

+    public abstract Reader getReader() throws IOException;

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/AbstractContentHandler.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/AbstractContentHandler.java
new file mode 100644
index 0000000..b5beda1
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/AbstractContentHandler.java
@@ -0,0 +1,115 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.descriptor.BodyDescriptor;

+

+import java.io.IOException;

+import java.io.InputStream;

+

+/**

+ * Abstract <code>ContentHandler</code> with default implementations of all

+ * the methods of the <code>ContentHandler</code> interface.

+ * 

+ * The default is to do nothing.

+ */

+public abstract class AbstractContentHandler implements ContentHandler {

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#endMultipart()

+     */

+    public void endMultipart() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#startMultipart(org.apache.james.mime4j.descriptor.BodyDescriptor)

+     */

+    public void startMultipart(BodyDescriptor bd) throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#body(org.apache.james.mime4j.descriptor.BodyDescriptor, java.io.InputStream)

+     */

+    public void body(BodyDescriptor bd, InputStream is)

+            throws MimeException, IOException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#endBodyPart()

+     */

+    public void endBodyPart() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#endHeader()

+     */

+    public void endHeader() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#endMessage()

+     */

+    public void endMessage() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#epilogue(java.io.InputStream)

+     */

+    public void epilogue(InputStream is) throws MimeException, IOException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#field(Field)

+     */

+    public void field(Field field) throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#preamble(java.io.InputStream)

+     */

+    public void preamble(InputStream is) throws MimeException, IOException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#startBodyPart()

+     */

+    public void startBodyPart() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#startHeader()

+     */

+    public void startHeader() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#startMessage()

+     */

+    public void startMessage() throws MimeException {

+    }

+    

+    /**

+     * @see org.apache.james.mime4j.parser.ContentHandler#raw(java.io.InputStream)

+     */

+    public void raw(InputStream is) throws MimeException, IOException {

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
new file mode 100644
index 0000000..188af6b
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/AbstractEntity.java
@@ -0,0 +1,389 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.IOException;
+import java.util.BitSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.descriptor.DefaultBodyDescriptor;
+import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
+import org.apache.james.mime4j.descriptor.MutableBodyDescriptor;
+import org.apache.james.mime4j.io.LineReaderInputStream;
+import org.apache.james.mime4j.io.MaxHeaderLimitException;
+import org.apache.james.mime4j.io.MaxLineLimitException;
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Abstract MIME entity.
+ */
+public abstract class AbstractEntity implements EntityStateMachine {
+
+    protected final Log log;
+    
+    protected final BodyDescriptor parent;
+    protected final int startState;
+    protected final int endState;
+    protected final MimeEntityConfig config;
+    protected final MutableBodyDescriptor body;
+    
+    protected int state;
+
+    private final ByteArrayBuffer linebuf;
+
+    private int lineCount;
+    private Field field;
+    private boolean endOfHeader;
+    private int headerCount;
+
+    private static final BitSet fieldChars = new BitSet();
+
+    static {
+        for (int i = 0x21; i <= 0x39; i++) {
+            fieldChars.set(i);
+        }
+        for (int i = 0x3b; i <= 0x7e; i++) {
+            fieldChars.set(i);
+        }
+    }
+
+    /**
+     * Internal state, not exposed.
+     */
+    private static final int T_IN_BODYPART = -2;
+    /**
+     * Internal state, not exposed.
+     */
+    private static final int T_IN_MESSAGE = -3;
+
+    AbstractEntity(
+            BodyDescriptor parent,
+            int startState, 
+            int endState,
+            MimeEntityConfig config) {
+        this.log = LogFactory.getLog(getClass());        
+        this.parent = parent;
+        this.state = startState;
+        this.startState = startState;
+        this.endState = endState;
+        this.config = config;
+        this.body = newBodyDescriptor(parent);
+        this.linebuf = new ByteArrayBuffer(64);
+        this.lineCount = 0;
+        this.endOfHeader = false;
+        this.headerCount = 0;
+    }
+
+    public int getState() {
+        return state;
+    }
+    
+    /**
+     * Creates a new instance of {@link BodyDescriptor}. Subclasses may override
+     * this in order to create body descriptors, that provide more specific
+     * information.
+     */
+    protected MutableBodyDescriptor newBodyDescriptor(BodyDescriptor pParent) {
+        final MutableBodyDescriptor result;
+        if (config.isMaximalBodyDescriptor()) {
+            result = new MaximalBodyDescriptor(pParent);
+        } else {
+            result = new DefaultBodyDescriptor(pParent);
+        }
+        return result;
+    }
+
+    /**
+     * Returns the current line number or <code>-1</code> if line number
+     * information is not available.
+     */
+    protected abstract int getLineNumber();
+    
+    protected abstract LineReaderInputStream getDataStream();
+    
+    private ByteArrayBuffer fillFieldBuffer() throws IOException, MimeException {
+        if (endOfHeader) 
+            throw new IllegalStateException();
+
+        int maxLineLen = config.getMaxLineLen();
+        LineReaderInputStream instream = getDataStream();
+        ByteArrayBuffer fieldbuf = new ByteArrayBuffer(64);
+
+        for (;;) {
+            // If there's still data stuck in the line buffer
+            // copy it to the field buffer
+            int len = linebuf.length();
+            if (maxLineLen > 0 && fieldbuf.length() + len >= maxLineLen) {
+                throw new MaxLineLimitException("Maximum line length limit exceeded");
+            }
+            if (len > 0) {
+                fieldbuf.append(linebuf.buffer(), 0, len);
+            }
+            linebuf.clear();
+            if (instream.readLine(linebuf) == -1) {
+                monitor(Event.HEADERS_PREMATURE_END);
+                endOfHeader = true;
+                break;
+            }
+            len = linebuf.length();
+            if (len > 0 && linebuf.byteAt(len - 1) == '\n') {
+                len--;
+            }
+            if (len > 0 && linebuf.byteAt(len - 1) == '\r') {
+                len--;
+            }
+            if (len == 0) {
+                // empty line detected 
+                endOfHeader = true;
+                break;
+            }
+            lineCount++;
+            if (lineCount > 1) {
+                int ch = linebuf.byteAt(0);
+                if (ch != CharsetUtil.SP && ch != CharsetUtil.HT) {
+                    // new header detected
+                    break;
+                }
+            }
+        }
+
+        return fieldbuf;
+    }
+
+    protected boolean parseField() throws MimeException, IOException {
+        int maxHeaderLimit = config.getMaxHeaderCount();
+        for (;;) {
+            if (endOfHeader) {
+                return false;
+            }
+            if (headerCount >= maxHeaderLimit) {
+                throw new MaxHeaderLimitException("Maximum header limit exceeded");
+            }
+
+            ByteArrayBuffer fieldbuf = fillFieldBuffer();
+            headerCount++;
+
+            // Strip away line delimiter
+            int len = fieldbuf.length();
+            if (len > 0 && fieldbuf.byteAt(len - 1) == '\n') {
+                len--;
+            }
+            if (len > 0 && fieldbuf.byteAt(len - 1) == '\r') {
+                len--;
+            }
+            fieldbuf.setLength(len);
+            
+            boolean valid = true;
+            
+            int pos = fieldbuf.indexOf((byte) ':');
+            if (pos <= 0) {
+                monitor(Event.INALID_HEADER);
+                valid = false;
+            } else {
+                for (int i = 0; i < pos; i++) {
+                    if (!fieldChars.get(fieldbuf.byteAt(i) & 0xff)) {
+                        monitor(Event.INALID_HEADER);
+                        valid = false;
+                        break;
+                    }
+                }
+            }
+            if (valid) {
+                field = new RawField(fieldbuf, pos);
+                body.addField(field);            
+                return true;
+            }
+        }
+    }
+
+    /**
+     * <p>Gets a descriptor for the current entity.
+     * This method is valid if {@link #getState()} returns:</p>
+     * <ul>
+     * <li>{@link EntityStates#T_BODY}</li>
+     * <li>{@link EntityStates#T_START_MULTIPART}</li>
+     * <li>{@link EntityStates#T_EPILOGUE}</li>
+     * <li>{@link EntityStates#T_PREAMBLE}</li>
+     * </ul>
+     * @return <code>BodyDescriptor</code>, not nulls
+     */
+    public BodyDescriptor getBodyDescriptor() {
+        switch (getState()) {
+        case EntityStates.T_BODY:
+        case EntityStates.T_START_MULTIPART:
+        case EntityStates.T_PREAMBLE:
+        case EntityStates.T_EPILOGUE:
+        case EntityStates.T_END_OF_STREAM:
+            return body;
+        default:
+            throw new IllegalStateException("Invalid state :" + stateToString(state));
+        }
+    }
+
+    /**
+     * This method is valid, if {@link #getState()} returns {@link EntityStates#T_FIELD}.
+     * @return String with the fields raw contents.
+     * @throws IllegalStateException {@link #getState()} returns another
+     *   value than {@link EntityStates#T_FIELD}.
+     */
+    public Field getField() {
+        switch (getState()) {
+        case EntityStates.T_FIELD:
+            return field;
+        default:
+            throw new IllegalStateException("Invalid state :" + stateToString(state));
+        }
+    }
+
+    /**
+     * Monitors the given event.
+     * Subclasses may override to perform actions upon events.
+     * Base implementation logs at warn.
+     * @param event <code>Event</code>, not null
+     * @throws MimeException subclasses may elect to throw this exception upon
+     * invalid content
+     * @throws IOException subclasses may elect to throw this exception
+     */
+    protected void monitor(Event event) throws MimeException, IOException {
+        if (config.isStrictParsing()) {
+            throw new MimeParseEventException(event);
+        } else {
+            warn(event);
+        }
+    }
+    
+    /**
+     * Creates an indicative message suitable for display
+     * based on the given event and the current state of the system.
+     * @param event <code>Event</code>, not null
+     * @return message suitable for use as a message in an exception
+     * or for logging
+     */
+    protected String message(Event event) {
+        final String message;
+        if (event == null) {
+            message = "Event is unexpectedly null.";
+        } else {
+            message = event.toString();
+        }
+
+        int lineNumber = getLineNumber();
+        if (lineNumber <= 0)
+            return message;
+        else
+            return "Line " + lineNumber + ": " + message;
+    }
+    
+    /**
+     * Logs (at warn) an indicative message based on the given event 
+     * and the current state of the system.
+     * @param event <code>Event</code>, not null
+     */
+    protected void warn(Event event) {
+        if (log.isWarnEnabled()) {
+            log.warn(message(event));
+        }
+    }
+    
+    /**
+     * Logs (at debug) an indicative message based on the given event
+     * and the current state of the system.
+     * @param event <code>Event</code>, not null
+     */
+    protected void debug(Event event) {
+        if (log.isDebugEnabled()) {
+            log.debug(message(event));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getName() + " [" + stateToString(state)
+        + "][" + body.getMimeType() + "][" + body.getBoundary() + "]";
+    }
+
+    /**
+     * Renders a state as a string suitable for logging.
+     * @param state 
+     * @return rendered as string, not null
+     */
+    public static final String stateToString(int state) {
+        final String result;
+        switch (state) {
+            case EntityStates.T_END_OF_STREAM:
+                result = "End of stream";
+                break;
+            case EntityStates.T_START_MESSAGE:
+                result = "Start message";
+                break;
+            case EntityStates.T_END_MESSAGE:
+                result = "End message";
+                break;
+            case EntityStates.T_RAW_ENTITY:
+                result = "Raw entity";
+                break;
+            case EntityStates.T_START_HEADER:
+                result = "Start header";
+                break;
+            case EntityStates.T_FIELD:
+                result = "Field";
+                break;
+            case EntityStates.T_END_HEADER:
+                result = "End header";
+                break;
+            case EntityStates.T_START_MULTIPART:
+                result = "Start multipart";
+                break;
+            case EntityStates.T_END_MULTIPART:
+                result = "End multipart";
+                break;
+            case EntityStates.T_PREAMBLE:
+                result = "Preamble";
+                break;
+            case EntityStates.T_EPILOGUE:
+                result = "Epilogue";
+                break;
+            case EntityStates.T_START_BODYPART:
+                result = "Start bodypart";
+                break;
+            case EntityStates.T_END_BODYPART:
+                result = "End bodypart";
+                break;
+            case EntityStates.T_BODY:
+                result = "Body";
+                break;
+            case T_IN_BODYPART:
+                result = "Bodypart";
+                break;
+            case T_IN_MESSAGE:
+                result = "In message";
+                break;
+            default:
+                result = "Unknown";
+                break;
+        }
+        return result;
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/ContentHandler.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/ContentHandler.java
new file mode 100644
index 0000000..45bb2d0
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/ContentHandler.java
@@ -0,0 +1,201 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.descriptor.BodyDescriptor;

+

+import java.io.IOException;

+import java.io.InputStream;

+

+/**

+ * <p>

+ * Receives notifications of the content of a plain RFC822 or MIME message.

+ * Implement this interface and register an instance of that implementation

+ * with a <code>MimeStreamParser</code> instance using its 

+ * {@link org.apache.james.mime4j.parser.MimeStreamParser#setContentHandler(ContentHandler)}

+ * method. The parser uses the <code>ContentHandler</code> instance to report

+ * basic message-related events like the start and end of the body of a

+ * part in a multipart MIME entity.

+ * </p>

+ * <p>

+ * Throwing an exception from an event method will terminate the message

+ * processing, i.e. no new events will be generated for that message. 

+ * <p>

+ * Events will be generated in the order the corresponding elements occur in

+ * the message stream parsed by the parser. E.g.:

+ * <pre>

+ *      startMessage()

+ *          startHeader()

+ *              field(...)

+ *              field(...)

+ *              ...

+ *          endHeader()

+ *          startMultipart()

+ *              preamble(...)

+ *              startBodyPart()

+ *                  startHeader()

+ *                      field(...)

+ *                      field(...)

+ *                      ...

+ *                  endHeader()

+ *                  body()

+ *              endBodyPart()

+ *              startBodyPart()

+ *                  startHeader()

+ *                      field(...)

+ *                      field(...)

+ *                      ...

+ *                  endHeader()

+ *                  body()

+ *              endBodyPart()

+ *              epilogue(...)

+ *          endMultipart()

+ *      endMessage()

+ * </pre>

+ * The above shows an example of a MIME message consisting of a multipart

+ * body containing two body parts.

+ * </p>

+ * <p>

+ * See MIME RFCs 2045-2049 for more information on the structure of MIME 

+ * messages and RFC 822 and 2822 for the general structure of Internet mail

+ * messages.

+ * </p>

+ */

+public interface ContentHandler {

+

+    /**

+     * Called when a new message starts (a top level message or an embedded 

+     * rfc822 message).

+     *

+     * @throws MimeException on processing errors

+     */

+    void startMessage() throws MimeException;

+

+    /**

+     * Called when a message ends.

+     *

+     * @throws MimeException on processing errors

+     */

+    void endMessage() throws MimeException;

+

+    /**

+     * Called when a new body part starts inside a

+     * <code>multipart/*</code> entity.

+     *

+     * @throws MimeException on processing errors

+     */

+    void startBodyPart() throws MimeException;

+

+    /**

+     * Called when a body part ends.

+     *

+     * @throws MimeException on processing errors

+     */

+    void endBodyPart() throws MimeException;

+

+    /**

+     * Called when a header (of a message or body part) is about to be parsed.

+     *

+     * @throws MimeException on processing errors

+     */

+    void startHeader() throws MimeException;

+

+    /**

+     * Called for each field of a header.

+     * 

+     * @param field the MIME field.

+     * @throws MimeException on processing errors

+     */

+    void field(Field field) throws MimeException;

+

+    /**

+     * Called when there are no more header fields in a message or body part.

+     *

+     * @throws MimeException on processing errors

+     */

+    void endHeader() throws MimeException;

+

+    /**

+     * Called for the preamble (whatever comes before the first body part)

+     * of a <code>multipart/*</code> entity.

+     * 

+     * @param is used to get the contents of the preamble.

+     * @throws MimeException on processing errors

+     * @throws IOException should be thrown on I/O errors.

+     */

+    void preamble(InputStream is) throws MimeException, IOException;

+

+    /**

+     * Called for the epilogue (whatever comes after the final body part) 

+     * of a <code>multipart/*</code> entity.

+     * 

+     * @param is used to get the contents of the epilogue.

+     * @throws MimeException on processing errors

+     * @throws IOException should be thrown on I/O errors.

+     */

+    void epilogue(InputStream is) throws MimeException, IOException;

+

+    /**

+     * Called when the body of a multipart entity is about to be parsed.

+     * 

+     * @param bd encapsulates the values (either read from the 

+     *        message stream or, if not present, determined implictly 

+     *        as described in the 

+     *        MIME rfc:s) of the <code>Content-Type</code> and 

+     *        <code>Content-Transfer-Encoding</code> header fields.

+     * @throws MimeException on processing errors

+     */

+    void startMultipart(BodyDescriptor bd) throws MimeException;

+

+    /**

+     * Called when the body of an entity has been parsed.

+     *

+     * @throws MimeException on processing errors

+     */

+    void endMultipart() throws MimeException;

+

+    /**

+     * Called when the body of a discrete (non-multipart) entity is about to 

+     * be parsed.

+     * 

+     * @param bd see {@link #startMultipart(BodyDescriptor)}

+     * @param is the contents of the body. NOTE: this is the raw body contents 

+     *           - it will not be decoded if encoded. The <code>bd</code>

+     *           parameter should be used to determine how the stream data

+     *           should be decoded.

+     * @throws MimeException on processing errors

+     * @throws IOException should be thrown on I/O errors.

+     */

+    void body(BodyDescriptor bd, InputStream is)

+        throws MimeException, IOException;

+

+    /**

+     * Called when a new entity (message or body part) starts and the 

+     * parser is in <code>raw</code> mode.

+     * 

+     * @param is the raw contents of the entity.

+     * @throws MimeException on processing errors

+     * @throws IOException should be thrown on I/O errors.

+     * @see MimeStreamParser#setRaw(boolean)

+     */

+    void raw(InputStream is) throws MimeException, IOException;

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/EntityStateMachine.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/EntityStateMachine.java
new file mode 100644
index 0000000..ef93aae
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/EntityStateMachine.java
@@ -0,0 +1,103 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.descriptor.BodyDescriptor;

+

+import java.io.IOException;

+import java.io.InputStream;

+

+/**

+ * Represents the interal state of a MIME entity, which is being retrieved 

+ * from an input stream by a MIME parser.

+ */

+public interface EntityStateMachine {

+

+    /**

+     * Return the current state of the entity.

+     * 

+     * @see EntityStates

+     * 

+     * @return current state

+     */

+    int getState();

+    

+    /**

+     * Sets the current recursion mode.

+     * The recursion mode specifies the approach taken to parsing parts.

+     * {@link RecursionMode#M_RAW} mode does not parse the part at all.

+     * {@link RecursionMode#M_RECURSE} mode recursively parses each mail

+     * when an <code>message/rfc822</code> part is encounted;

+     * {@link RecursionMode#M_NO_RECURSE} does not.

+     * 

+     * @see RecursionMode

+     * 

+     * @param recursionMode

+     */

+    void setRecursionMode(int recursionMode);

+    

+    /**

+     * Advances the state machine to the next state in the 

+     * process of the MIME stream parsing. This method 

+     * may return an new state machine that represents an embedded 

+     * entity, which must be parsed before the parsing process of 

+     * the current entity can proceed.

+     * 

+     * @return a state machine of an embedded entity, if encountered, 

+     * <code>null</code> otherwise.

+     *  

+     * @throws IOException if an I/O error occurs.

+     * @throws MimeException if the message can not be processed due 

+     *  to the MIME specification violation.

+     */

+    EntityStateMachine advance() throws IOException, MimeException;

+    

+    /**

+     * Returns description of the entity body.

+     * 

+     * @return body description

+     * 

+     * @throws IllegalStateException if the body description cannot be

+     *  obtained at the current stage of the parsing process. 

+     */

+    BodyDescriptor getBodyDescriptor() throws IllegalStateException;

+    

+    /**

+     * Returns content stream of the entity body.

+     * 

+     * @return input stream

+     * 

+     * @throws IllegalStateException if the content stream cannot be

+     *  obtained at the current stage of the parsing process. 

+     */

+    InputStream getContentStream() throws IllegalStateException;

+ 

+    /**

+     * Returns current header field.

+     * 

+     * @return header field

+     * 

+     * @throws IllegalStateException if a header field cannot be

+     *  obtained at the current stage of the parsing process. 

+     */

+    Field getField() throws IllegalStateException;

+    

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/EntityStates.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/EntityStates.java
new file mode 100644
index 0000000..8686332
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/EntityStates.java
@@ -0,0 +1,95 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+/**

+ * Enumeration of states an entity is expected to go through

+ * in the process of the MIME stream parsing.

+ */

+public interface EntityStates {

+

+    /**

+     * This token indicates, that the MIME stream has been completely

+     * and successfully parsed, and no more data is available.

+     */

+    int T_END_OF_STREAM = -1;

+    /**

+     * This token indicates, that the MIME stream is currently

+     * at the beginning of a message.

+     */

+    int T_START_MESSAGE = 0;

+    /**

+     * This token indicates, that the MIME stream is currently

+     * at the end of a message.

+     */

+    int T_END_MESSAGE = 1;

+    /**

+     * This token indicates, that a raw entity is currently being processed.

+     */

+    int T_RAW_ENTITY = 2;

+    /**

+     * This token indicates, that a message parts headers are now

+     * being parsed.

+     */

+    int T_START_HEADER = 3;

+    /**

+     * This token indicates, that a message parts field has now

+     * been parsed. 

+     */

+    int T_FIELD = 4;

+    /**

+     * This token indicates, that part headers have now been

+     * parsed.

+     */

+    int T_END_HEADER = 5;

+    /**

+     * This token indicates, that a multipart body is being parsed.

+     */

+    int T_START_MULTIPART = 6;

+    /**

+     * This token indicates, that a multipart body has been parsed.

+     */

+    int T_END_MULTIPART = 7;

+    /**

+     * This token indicates, that a multiparts preamble is being

+     * parsed. 

+     */

+    int T_PREAMBLE = 8;

+    /**

+     * This token indicates, that a multiparts epilogue is being

+     * parsed. 

+     */

+    int T_EPILOGUE = 9;

+    /**

+     * This token indicates, that the MIME stream is currently

+     * at the beginning of a body part.

+     */

+    int T_START_BODYPART = 10;

+    /**

+     * This token indicates, that the MIME stream is currently

+     * at the end of a body part.

+     */

+    int T_END_BODYPART = 11;

+    /**

+     * This token indicates, that an atomic entity is being parsed.

+     */

+    int T_BODY = 12;

+

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/Event.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/Event.java
new file mode 100644
index 0000000..5027cfa
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/Event.java
@@ -0,0 +1,71 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+/**

+ * Enumerates events which can be monitored.

+ */

+public final class Event { 

+

+    /** Indicates that a body part ended prematurely. */

+    public static final Event MIME_BODY_PREMATURE_END 

+        = new Event("Body part ended prematurely. " +

+                "Boundary detected in header or EOF reached."); 

+    /** Indicates that unexpected end of headers detected.*/

+    public static final Event HEADERS_PREMATURE_END 

+        = new Event("Unexpected end of headers detected. " +

+                "Higher level boundary detected or EOF reached.");

+    /** Indicates that unexpected end of headers detected.*/

+    public static final Event INALID_HEADER 

+        = new Event("Invalid header encountered");

+    

+    private final String code;

+    

+    public Event(final String code) {

+        super();

+        if (code == null) {

+            throw new IllegalArgumentException("Code may not be null");

+        }

+        this.code = code;

+    }

+    

+    @Override

+    public int hashCode() {

+        return code.hashCode();

+    }

+

+    @Override

+    public boolean equals(Object obj) {

+        if (obj == null) return false;

+        if (this == obj) return true;

+        if (obj instanceof Event) {

+            Event that = (Event) obj;

+            return this.code.equals(that.code);

+        } else {

+            return false;

+        }

+    }

+    

+    @Override

+    public String toString() {

+        return code;

+    }

+    

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/Field.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/Field.java
new file mode 100644
index 0000000..dac698b
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/Field.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Abstract MIME field.
+ */
+public interface Field {
+    
+    /**
+     * Gets the name of the field (<code>Subject</code>, <code>From</code>, etc).
+     * 
+     * @return the field name.
+     */
+    String getName();
+
+    /**
+     * Gets the unparsed and possibly encoded (see RFC 2047) field body string.
+     * 
+     * @return the unparsed field body string.
+     */
+    String getBody();
+
+    /**
+     * Gets the original raw field bytes.
+     * 
+     * @return the original raw field bytes.
+     */
+    ByteSequence getRaw();
+    
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
new file mode 100644
index 0000000..b1a8b0f
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeEntity.java
@@ -0,0 +1,320 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.Base64InputStream;
+import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
+import org.apache.james.mime4j.io.LimitedInputStream;
+import org.apache.james.mime4j.io.LineNumberSource;
+import org.apache.james.mime4j.io.LineReaderInputStream;
+import org.apache.james.mime4j.io.LineReaderInputStreamAdaptor;
+import org.apache.james.mime4j.io.MimeBoundaryInputStream;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.util.MimeUtil;
+
+public class MimeEntity extends AbstractEntity {
+
+    /**
+     * Internal state, not exposed.
+     */
+    private static final int T_IN_BODYPART = -2;
+    /**
+     * Internal state, not exposed.
+     */
+    private static final int T_IN_MESSAGE = -3;
+
+    private final LineNumberSource lineSource;
+    private final BufferedLineReaderInputStream inbuffer;
+    
+    private int recursionMode;
+    private MimeBoundaryInputStream mimeStream;
+    private LineReaderInputStreamAdaptor dataStream;
+    private boolean skipHeader;
+    
+    private byte[] tmpbuf;
+    
+    public MimeEntity(
+            LineNumberSource lineSource,
+            BufferedLineReaderInputStream inbuffer,
+            BodyDescriptor parent, 
+            int startState, 
+            int endState,
+            MimeEntityConfig config) {
+        super(parent, startState, endState, config);
+        this.lineSource = lineSource;
+        this.inbuffer = inbuffer;
+        this.dataStream = new LineReaderInputStreamAdaptor(
+                inbuffer,
+                config.getMaxLineLen());
+        this.skipHeader = false;
+    }
+
+    public MimeEntity(
+            LineNumberSource lineSource,
+            BufferedLineReaderInputStream inbuffer,
+            BodyDescriptor parent, 
+            int startState, 
+            int endState) {
+        this(lineSource, inbuffer, parent, startState, endState, 
+                new MimeEntityConfig());
+    }
+
+    public int getRecursionMode() {
+        return recursionMode;
+    }
+
+    public void setRecursionMode(int recursionMode) {
+        this.recursionMode = recursionMode;
+    }
+
+    public void skipHeader(String contentType) {
+        if (state != EntityStates.T_START_MESSAGE) {
+            throw new IllegalStateException("Invalid state: " + stateToString(state));
+        }
+        skipHeader = true;
+        ByteSequence raw = ContentUtil.encode("Content-Type: " + contentType);
+        body.addField(new RawField(raw, 12));
+    }
+
+    @Override
+    protected int getLineNumber() {
+        if (lineSource == null)
+            return -1;
+        else
+            return lineSource.getLineNumber();
+    }
+    
+    @Override
+    protected LineReaderInputStream getDataStream() {
+        return dataStream;
+    }
+    
+    public EntityStateMachine advance() throws IOException, MimeException {
+        switch (state) {
+        case EntityStates.T_START_MESSAGE:
+            if (skipHeader) {
+                state = EntityStates.T_END_HEADER;
+            } else {
+                state = EntityStates.T_START_HEADER;
+            }
+            break;
+        case EntityStates.T_START_BODYPART:
+            state = EntityStates.T_START_HEADER;
+            break;
+        case EntityStates.T_START_HEADER:
+        case EntityStates.T_FIELD:
+            state = parseField() ? EntityStates.T_FIELD : EntityStates.T_END_HEADER;
+            break;
+        case EntityStates.T_END_HEADER:
+            String mimeType = body.getMimeType();
+            if (recursionMode == RecursionMode.M_FLAT) {
+                state = EntityStates.T_BODY;
+            } else if (MimeUtil.isMultipart(mimeType)) {
+                state = EntityStates.T_START_MULTIPART;
+                clearMimeStream();
+            } else if (recursionMode != RecursionMode.M_NO_RECURSE 
+                    && MimeUtil.isMessage(mimeType)) {
+                state = T_IN_MESSAGE;
+                return nextMessage();
+            } else {
+                state = EntityStates.T_BODY;
+            }
+            break;
+        case EntityStates.T_START_MULTIPART:
+            if (dataStream.isUsed()) {
+                advanceToBoundary();            
+                state = EntityStates.T_END_MULTIPART;
+            } else {
+                createMimeStream();
+                state = EntityStates.T_PREAMBLE;
+            }
+            break;
+        case EntityStates.T_PREAMBLE:
+            advanceToBoundary();            
+            if (mimeStream.isLastPart()) {
+                clearMimeStream();
+                state = EntityStates.T_END_MULTIPART;
+            } else {
+                clearMimeStream();
+                createMimeStream();
+                state = T_IN_BODYPART;
+                return nextMimeEntity();
+            }
+            break;
+        case T_IN_BODYPART:
+            advanceToBoundary();
+            if (mimeStream.eof() && !mimeStream.isLastPart()) {
+                monitor(Event.MIME_BODY_PREMATURE_END);
+            } else {
+                if (!mimeStream.isLastPart()) {
+                    clearMimeStream();
+                    createMimeStream();
+                    state = T_IN_BODYPART;
+                    return nextMimeEntity();
+                }
+            }
+            clearMimeStream();
+            state = EntityStates.T_EPILOGUE;
+            break;
+        case EntityStates.T_EPILOGUE:
+            state = EntityStates.T_END_MULTIPART;
+            break;
+        case EntityStates.T_BODY:
+        case EntityStates.T_END_MULTIPART:
+        case T_IN_MESSAGE:
+            state = endState;
+            break;
+        default:
+            if (state == endState) {
+                state = EntityStates.T_END_OF_STREAM;
+                break;
+            }
+            throw new IllegalStateException("Invalid state: " + stateToString(state));
+        }
+        return null;
+    }
+
+    private void createMimeStream() throws MimeException, IOException {
+        String boundary = body.getBoundary();
+        int bufferSize = 2 * boundary.length();
+        if (bufferSize < 4096) {
+            bufferSize = 4096;
+        }
+        try {
+            if (mimeStream != null) {
+                mimeStream = new MimeBoundaryInputStream(
+                        new BufferedLineReaderInputStream(
+                                mimeStream, 
+                                bufferSize, 
+                                config.getMaxLineLen()), 
+                        boundary);
+            } else {
+                inbuffer.ensureCapacity(bufferSize);
+                mimeStream = new MimeBoundaryInputStream(inbuffer, boundary);
+            }
+        } catch (IllegalArgumentException e) {
+            // thrown when boundary is too long
+            throw new MimeException(e.getMessage(), e);
+        }
+        dataStream = new LineReaderInputStreamAdaptor(
+                mimeStream,
+                config.getMaxLineLen()); 
+    }
+    
+    private void clearMimeStream() {
+        mimeStream = null;
+        dataStream = new LineReaderInputStreamAdaptor(
+                inbuffer,
+                config.getMaxLineLen()); 
+    }
+    
+    private void advanceToBoundary() throws IOException {
+        if (!dataStream.eof()) {
+            if (tmpbuf == null) {
+                tmpbuf = new byte[2048];
+            }
+            InputStream instream = getLimitedContentStream();
+            while (instream.read(tmpbuf)!= -1) {
+            }
+        }
+    }
+    
+    private EntityStateMachine nextMessage() {
+        String transferEncoding = body.getTransferEncoding();
+        InputStream instream;
+        if (MimeUtil.isBase64Encoding(transferEncoding)) {
+            log.debug("base64 encoded message/rfc822 detected");
+            instream = new Base64InputStream(dataStream);                    
+        } else if (MimeUtil.isQuotedPrintableEncoded(transferEncoding)) {
+            log.debug("quoted-printable encoded message/rfc822 detected");
+            instream = new QuotedPrintableInputStream(dataStream);                    
+        } else {
+            instream = dataStream;
+        }
+        
+        if (recursionMode == RecursionMode.M_RAW) {
+            RawEntity message = new RawEntity(instream);
+            return message;
+        } else {
+            MimeEntity message = new MimeEntity(
+                    lineSource, 
+                    new BufferedLineReaderInputStream(
+                            instream, 
+                            4 * 1024,
+                            config.getMaxLineLen()),
+                    body, 
+                    EntityStates.T_START_MESSAGE, 
+                    EntityStates.T_END_MESSAGE,
+                    config);
+            message.setRecursionMode(recursionMode);
+            return message;
+        }
+    }
+    
+    private EntityStateMachine nextMimeEntity() {
+        if (recursionMode == RecursionMode.M_RAW) {
+            RawEntity message = new RawEntity(mimeStream);
+            return message;
+        } else {
+            BufferedLineReaderInputStream stream = new BufferedLineReaderInputStream(
+                    mimeStream, 
+                    4 * 1024,
+                    config.getMaxLineLen());
+            MimeEntity mimeentity = new MimeEntity(
+                    lineSource, 
+                    stream,
+                    body, 
+                    EntityStates.T_START_BODYPART, 
+                    EntityStates.T_END_BODYPART,
+                    config);
+            mimeentity.setRecursionMode(recursionMode);
+            return mimeentity;
+        }
+    }
+    
+    private InputStream getLimitedContentStream() {
+        long maxContentLimit = config.getMaxContentLen();
+        if (maxContentLimit >= 0) {
+            return new LimitedInputStream(dataStream, maxContentLimit);
+        } else {
+            return dataStream;
+        }
+    }
+    
+    public InputStream getContentStream() {
+        switch (state) {
+        case EntityStates.T_START_MULTIPART:
+        case EntityStates.T_PREAMBLE:
+        case EntityStates.T_EPILOGUE:
+        case EntityStates.T_BODY:
+            return getLimitedContentStream();
+        default:
+            throw new IllegalStateException("Invalid state: " + stateToString(state));
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java
new file mode 100644
index 0000000..8995af5
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeEntityConfig.java
@@ -0,0 +1,181 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.MimeException;
+
+/**
+ * MIME entity configuration
+ */
+public final class MimeEntityConfig implements Cloneable {
+
+    private boolean maximalBodyDescriptor;
+    private boolean strictParsing;
+    private int maxLineLen;
+    private int maxHeaderCount;
+    private long maxContentLen;
+    private boolean countLineNumbers;
+    
+    public MimeEntityConfig() {
+        this.maximalBodyDescriptor = false;
+        this.strictParsing = false;
+        this.maxLineLen = 1000;
+        this.maxHeaderCount = 1000;
+        this.maxContentLen = -1;
+        this.countLineNumbers = false;
+    }
+    
+    public boolean isMaximalBodyDescriptor() {
+        return this.maximalBodyDescriptor;
+    }
+    
+    public void setMaximalBodyDescriptor(boolean maximalBodyDescriptor) {
+        this.maximalBodyDescriptor = maximalBodyDescriptor;
+    }
+    
+    /**
+     * Defines whether minor violations of the MIME specification should be 
+     * tolerated or should result in a {@link MimeException}. If this parameter
+     * is set to <code>true</code>, a strict interpretation of the MIME 
+     * specification will be enforced, If this parameter is set to <code>false</code>
+     * minor violations will result in a warning in the log.
+     * 
+     * @param strictParsing value of the strict parsing mode
+     */
+    public void setStrictParsing(boolean strictParsing) {
+        this.strictParsing = strictParsing;
+    }
+
+    /**
+     * Returns the value of the strict parsing mode
+     * @see #setStrictParsing(boolean)
+     * 
+     * @return value of the strict parsing mode
+     */
+    public boolean isStrictParsing() {
+        return this.strictParsing;
+    }
+    
+    /**
+     * Sets the maximum line length limit. Parsing of a MIME entity will be terminated 
+     * with a {@link MimeException} if a line is encountered that exceeds the maximum
+     * length limit. If this parameter is set to a non positive value the line length
+     * check will be disabled.
+     * 
+     * @param maxLineLen maximum line length limit
+     */
+    public void setMaxLineLen(int maxLineLen) {
+        this.maxLineLen = maxLineLen;
+    }
+    
+    /** 
+     * Returns the maximum line length limit
+     * @see #setMaxLineLen(int)
+     * 
+     * @return value of the the maximum line length limit
+     */
+    public int getMaxLineLen() {
+        return this.maxLineLen;
+    }
+
+    /**
+     * Sets the maximum header limit. Parsing of a MIME entity will be terminated 
+     * with a {@link MimeException} if the number of headers exceeds the maximum
+     * limit. If this parameter is set to a non positive value the header limit check 
+     * will be disabled.
+     * 
+     * @param maxHeaderCount maximum header limit
+     */
+    public void setMaxHeaderCount(int maxHeaderCount) {
+        this.maxHeaderCount = maxHeaderCount;
+    }
+
+    /** 
+     * Returns the maximum header limit
+     * @see #setMaxHeaderCount(int)
+     * 
+     * @return value of the the maximum header limit
+     */
+    public int getMaxHeaderCount() {
+        return this.maxHeaderCount;
+    }
+
+    /**
+     * Sets the maximum content length limit. Parsing of a MIME entity will be terminated 
+     * with a {@link MimeException} if a content body exceeds the maximum length limit. 
+     * If this parameter is set to a non positive value the content length
+     * check will be disabled.
+     * 
+     * @param maxContentLen maximum content length limit
+     */
+    public void setMaxContentLen(long maxContentLen) {
+        this.maxContentLen = maxContentLen;
+    }
+
+    /** 
+     * Returns the maximum content length limit
+     * @see #setMaxContentLen(long)
+     * 
+     * @return value of the the maximum content length limit
+     */
+    public long getMaxContentLen() {
+        return maxContentLen;
+    }
+
+    /**
+     * Defines whether the parser should count line numbers. If enabled line
+     * numbers are included in the debug output.
+     * 
+     * @param countLineNumbers
+     *            value of the line number counting mode.
+     */
+    public void setCountLineNumbers(boolean countLineNumbers) {
+        this.countLineNumbers = countLineNumbers;
+    }
+
+    /**
+     * Returns the value of the line number counting mode.
+     * 
+     * @return value of the line number counting mode.
+     */
+    public boolean isCountLineNumbers() {
+        return countLineNumbers;
+    }
+
+    @Override
+    public MimeEntityConfig clone() {
+        try {
+            return (MimeEntityConfig) super.clone();
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+    }
+    
+    @Override
+    public String toString() {
+        return "[max body descriptor: " + maximalBodyDescriptor
+                + ", strict parsing: " + strictParsing + ", max line length: "
+                + maxLineLen + ", max header count: " + maxHeaderCount
+                + ", max content length: " + maxContentLen
+                + ", count line numbers: " + countLineNumbers + "]";
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeParseEventException.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeParseEventException.java
new file mode 100644
index 0000000..5d02909
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeParseEventException.java
@@ -0,0 +1,50 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.MimeException;
+
+/**
+ * Indicates that strict parsing has been enabled 
+ * and an optional invality has been found in the input.
+ * {@link #getEvent()} indicates the type of invalidity.
+ */
+public class MimeParseEventException extends MimeException {
+    
+    private static final long serialVersionUID = 4632991604246852302L;
+    private final Event event;
+    
+    /**
+     * Constructs an exception 
+     * @param event <code>MimeTokenStream.Event</code>, not null
+     */
+    public MimeParseEventException(final Event event) {
+        super(event.toString());
+        this.event = event;
+    }
+
+    /**
+     * Gets the causal parse event.
+     * @return <code>MimeTokenStream.Event</code>, not null
+     */
+    public Event getEvent() {
+        return event;
+    }
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java
new file mode 100644
index 0000000..f64fba4
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java
@@ -0,0 +1,199 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <p>
+ * Parses MIME (or RFC822) message streams of bytes or characters and reports 
+ * parsing events to a <code>ContentHandler</code> instance.
+ * </p>
+ * <p>
+ * Typical usage:<br/>
+ * <pre>
+ *      ContentHandler handler = new MyHandler();
+ *      MimeStreamParser parser = new MimeStreamParser();
+ *      parser.setContentHandler(handler);
+ *      parser.parse(new FileInputStream("mime.msg"));
+ * </pre>
+ */
+public class MimeStreamParser {
+
+    private ContentHandler handler = null;
+    private boolean contentDecoding;
+    
+    private final MimeTokenStream mimeTokenStream;
+
+    public MimeStreamParser(final MimeEntityConfig config) {
+        super();
+        MimeEntityConfig localConfig;
+        if (config != null) {
+            localConfig = config.clone();
+        } else {
+            localConfig = new MimeEntityConfig();
+        }
+        this.mimeTokenStream = new MimeTokenStream(localConfig);
+        this.contentDecoding = false;
+    }
+    
+    public MimeStreamParser() {
+        this(null);
+    }
+    
+    /**
+     * Determines whether this parser automatically decodes body content
+     * based on the on the MIME fields with the standard defaults.
+     */ 
+    public boolean isContentDecoding() {
+        return contentDecoding;
+    }
+
+    /**
+     * Defines whether parser should automatically decode body content
+     * based on the on the MIME fields with the standard defaults.
+     */ 
+    public void setContentDecoding(boolean b) {
+        this.contentDecoding = b;
+    }
+
+    /**
+     * Parses a stream of bytes containing a MIME message.
+     * 
+     * @param is the stream to parse.
+     * @throws MimeException if the message can not be processed
+     * @throws IOException on I/O errors.
+     */
+    public void parse(InputStream is) throws MimeException, IOException {
+        mimeTokenStream.parse(is);
+        OUTER: for (;;) {
+            int state = mimeTokenStream.getState();
+            switch (state) {
+                case MimeTokenStream.T_BODY:
+                    BodyDescriptor desc = mimeTokenStream.getBodyDescriptor();
+                    InputStream bodyContent;
+                    if (contentDecoding) {
+                        bodyContent = mimeTokenStream.getDecodedInputStream(); 
+                    } else {
+                        bodyContent = mimeTokenStream.getInputStream(); 
+                    }
+                    handler.body(desc, bodyContent);
+                    break;
+                case MimeTokenStream.T_END_BODYPART:
+                    handler.endBodyPart();
+                    break;
+                case MimeTokenStream.T_END_HEADER:
+                    handler.endHeader();
+                    break;
+                case MimeTokenStream.T_END_MESSAGE:
+                    handler.endMessage();
+                    break;
+                case MimeTokenStream.T_END_MULTIPART:
+                    handler.endMultipart();
+                    break;
+                case MimeTokenStream.T_END_OF_STREAM:
+                    break OUTER;
+                case MimeTokenStream.T_EPILOGUE:
+                    handler.epilogue(mimeTokenStream.getInputStream());
+                    break;
+                case MimeTokenStream.T_FIELD:
+                    handler.field(mimeTokenStream.getField());
+                    break;
+                case MimeTokenStream.T_PREAMBLE:
+                    handler.preamble(mimeTokenStream.getInputStream());
+                    break;
+                case MimeTokenStream.T_RAW_ENTITY:
+                    handler.raw(mimeTokenStream.getInputStream());
+                    break;
+                case MimeTokenStream.T_START_BODYPART:
+                    handler.startBodyPart();
+                    break;
+                case MimeTokenStream.T_START_HEADER:
+                    handler.startHeader();
+                    break;
+                case MimeTokenStream.T_START_MESSAGE:
+                    handler.startMessage();
+                    break;
+                case MimeTokenStream.T_START_MULTIPART:
+                    handler.startMultipart(mimeTokenStream.getBodyDescriptor());
+                    break;
+                default:
+                    throw new IllegalStateException("Invalid state: " + state);
+            }
+            state = mimeTokenStream.next();
+        }
+    }
+    
+    /**
+     * Determines if this parser is currently in raw mode.
+     * 
+     * @return <code>true</code> if in raw mode, <code>false</code>
+     *         otherwise.
+     * @see #setRaw(boolean)
+     */
+    public boolean isRaw() {
+        return mimeTokenStream.isRaw();
+    }
+    
+    /**
+     * Enables or disables raw mode. In raw mode all future entities 
+     * (messages or body parts) in the stream will be reported to the
+     * {@link ContentHandler#raw(InputStream)} handler method only.
+     * The stream will contain the entire unparsed entity contents 
+     * including header fields and whatever is in the body.
+     * 
+     * @param raw <code>true</code> enables raw mode, <code>false</code>
+     *        disables it.
+     */
+    public void setRaw(boolean raw) {
+        mimeTokenStream.setRecursionMode(MimeTokenStream.M_RAW);
+    }
+    
+    /**
+     * Finishes the parsing and stops reading lines.
+     * NOTE: No more lines will be parsed but the parser
+     * will still call 
+     * {@link ContentHandler#endMultipart()},
+     * {@link ContentHandler#endBodyPart()},
+     * {@link ContentHandler#endMessage()}, etc to match previous calls
+     * to 
+     * {@link ContentHandler#startMultipart(BodyDescriptor)},
+     * {@link ContentHandler#startBodyPart()},
+     * {@link ContentHandler#startMessage()}, etc.
+     */
+    public void stop() {
+        mimeTokenStream.stop();
+    }
+    
+    /**
+     * Sets the <code>ContentHandler</code> to use when reporting 
+     * parsing events.
+     * 
+     * @param h the <code>ContentHandler</code>.
+     */
+    public void setContentHandler(ContentHandler h) {
+        this.handler = h;
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeTokenStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeTokenStream.java
new file mode 100644
index 0000000..36412cf
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/MimeTokenStream.java
@@ -0,0 +1,385 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.LinkedList;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.Base64InputStream;
+import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
+import org.apache.james.mime4j.io.LineNumberInputStream;
+import org.apache.james.mime4j.io.LineNumberSource;
+import org.apache.james.mime4j.util.CharsetUtil;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * <p>
+ * Parses MIME (or RFC822) message streams of bytes or characters.
+ * The stream is converted into an event stream.
+ * <p>
+ * <p>
+ * Typical usage:
+ * </p>
+ * <pre>
+ *      MimeTokenStream stream = new MimeTokenStream();
+ *      stream.parse(new FileInputStream("mime.msg"));
+ *      for (int state = stream.getState();
+ *           state != MimeTokenStream.T_END_OF_STREAM;
+ *           state = stream.next()) {
+ *          switch (state) {
+ *            case MimeTokenStream.T_BODY:
+ *              System.out.println("Body detected, contents = "
+ *                + stream.getInputStream() + ", header data = "
+ *                + stream.getBodyDescriptor());
+ *              break;
+ *            case MimeTokenStream.T_FIELD:
+ *              System.out.println("Header field detected: "
+ *                + stream.getField());
+ *              break;
+ *            case MimeTokenStream.T_START_MULTIPART:
+ *              System.out.println("Multipart message detexted,"
+ *                + " header data = "
+ *                + stream.getBodyDescriptor());
+ *            ...
+ *          }
+ *      }
+ * </pre>
+ * <p>Instances of {@link MimeTokenStream} are reusable: Invoking the
+ * method {@link #parse(InputStream)} resets the token streams internal
+ * state. However, they are definitely <em>not</em> thread safe. If you
+ * have a multi threaded application, then the suggested use is to have
+ * one instance per thread.</p>
+ */
+public class MimeTokenStream implements EntityStates, RecursionMode {
+    
+    /**
+     * Creates a stream that creates a more detailed body descriptor.
+     * @return <code>MimeTokenStream</code>, not null
+     */
+    public static final MimeTokenStream createMaximalDescriptorStream() {
+        MimeEntityConfig config = new MimeEntityConfig();
+        config.setMaximalBodyDescriptor(true);
+        return new MimeTokenStream(config);
+    }
+    
+    /**
+     * Creates a stream that strictly validates the input.
+     * @return <code>MimeTokenStream</code> which throws a 
+     * <code>MimeException</code> whenever possible issues 
+     * are dedicated in the input
+     */
+    public static final MimeTokenStream createStrictValidationStream() {
+        MimeEntityConfig config = new MimeEntityConfig();
+        config.setStrictParsing(true);
+        return new MimeTokenStream(config);
+    }
+    
+    private final MimeEntityConfig config;
+    private final LinkedList<EntityStateMachine> entities = new LinkedList<EntityStateMachine>();
+    
+    private int state = T_END_OF_STREAM;
+    private EntityStateMachine currentStateMachine;
+    private int recursionMode = M_RECURSE;
+    private BufferedLineReaderInputStream inbuffer;
+    
+    /**
+     * Constructs a standard (lax) stream.
+     * Optional validation events will be logged only.
+     * Use {@link #createStrictValidationStream()} to create
+     * a stream that strictly validates the input.
+     */
+    public MimeTokenStream() {
+        this(new MimeEntityConfig());
+    }
+    
+    protected MimeTokenStream(final MimeEntityConfig config) {
+        super();
+        this.config = config;
+    }
+    
+    /** Instructs the {@code MimeTokenStream} to parse the given streams contents.
+     * If the {@code MimeTokenStream} has already been in use, resets the streams
+     * internal state.
+     */
+    public void parse(InputStream stream) {
+        doParse(stream, null);
+    }
+
+    /** Instructs the {@code MimeTokenStream} to parse the given content with 
+     * the content type. The message stream is assumed to have no message header
+     * and is expected to begin with a message body. This can be the case when 
+     * the message content is transmitted using a different transport protocol 
+     * such as HTTP.
+     * <p/>
+     * If the {@code MimeTokenStream} has already been in use, resets the streams
+     * internal state.
+     */    
+    public void parseHeadless(InputStream stream, String contentType) {
+        if (contentType == null) {
+            throw new IllegalArgumentException("Content type may not be null");
+        }
+        doParse(stream, contentType);
+    }
+
+    private void doParse(InputStream stream, String contentType) {
+        entities.clear();
+
+        LineNumberSource lineSource = null;
+        if (config.isCountLineNumbers()) {
+            LineNumberInputStream lineInput = new LineNumberInputStream(stream);
+            lineSource = lineInput;
+            stream = lineInput;
+        }
+
+        inbuffer = new BufferedLineReaderInputStream(
+                stream, 
+                4 * 1024,
+                config.getMaxLineLen());
+        switch (recursionMode) {
+        case M_RAW:
+            RawEntity rawentity = new RawEntity(inbuffer);
+            currentStateMachine = rawentity;
+            break;
+        case M_NO_RECURSE:
+        case M_FLAT:
+            // expected to be called only at start of paring
+        case M_RECURSE:
+            MimeEntity mimeentity = new MimeEntity(
+                    lineSource,
+                    inbuffer,
+                    null, 
+                    T_START_MESSAGE, 
+                    T_END_MESSAGE,
+                    config);
+            mimeentity.setRecursionMode(recursionMode);
+            if (contentType != null) {
+                mimeentity.skipHeader(contentType);
+            }
+            currentStateMachine = mimeentity;
+            break;
+        }
+        entities.add(currentStateMachine);
+        state = currentStateMachine.getState();
+    }
+
+    /**
+     * Determines if this parser is currently in raw mode.
+     * 
+     * @return <code>true</code> if in raw mode, <code>false</code>
+     *         otherwise.
+     * @see #setRecursionMode(int)
+     */
+    public boolean isRaw() {
+        return recursionMode == M_RAW;
+    }
+    
+    /**
+     * Gets the current recursion mode.
+     * The recursion mode specifies the approach taken to parsing parts.
+     * {@link #M_RAW}  mode does not parse the part at all.
+     * {@link #M_RECURSE} mode recursively parses each mail
+     * when an <code>message/rfc822</code> part is encounted;
+     * {@link #M_NO_RECURSE} does not.
+     * @return {@link #M_RECURSE}, {@link #M_RAW} or {@link #M_NO_RECURSE}
+     */
+    public int getRecursionMode() {
+        return recursionMode;
+    }
+    
+    /**
+     * Sets the current recursion.
+     * The recursion mode specifies the approach taken to parsing parts.
+     * {@link #M_RAW}  mode does not parse the part at all.
+     * {@link #M_RECURSE} mode recursively parses each mail
+     * when an <code>message/rfc822</code> part is encounted;
+     * {@link #M_NO_RECURSE} does not.
+     * @param mode {@link #M_RECURSE}, {@link #M_RAW} or {@link #M_NO_RECURSE}
+     */
+    public void setRecursionMode(int mode) {
+        recursionMode = mode;
+        if (currentStateMachine != null) {
+            currentStateMachine.setRecursionMode(mode);
+        }
+    }
+
+    /**
+     * Finishes the parsing and stops reading lines.
+     * NOTE: No more lines will be parsed but the parser
+     * will still call 
+     * {@link ContentHandler#endMultipart()},
+     * {@link ContentHandler#endBodyPart()},
+     * {@link ContentHandler#endMessage()}, etc to match previous calls
+     * to 
+     * {@link ContentHandler#startMultipart(BodyDescriptor)},
+     * {@link ContentHandler#startBodyPart()},
+     * {@link ContentHandler#startMessage()}, etc.
+     */
+    public void stop() {
+        inbuffer.truncate();
+    }
+
+    /**
+     * Returns the current state.
+     */
+    public int getState() {
+        return state;
+    }
+
+    /**
+     * This method returns the raw entity, preamble, or epilogue contents.
+     * <p/>
+     * This method is valid, if {@link #getState()} returns either of
+     * {@link #T_RAW_ENTITY}, {@link #T_PREAMBLE}, or {@link #T_EPILOGUE}.
+     * 
+     * @return Data stream, depending on the current state.
+     * @throws IllegalStateException {@link #getState()} returns an
+     *   invalid value.
+     */
+    public InputStream getInputStream() {
+        return currentStateMachine.getContentStream();
+    }
+    
+    /**
+     * This method returns a transfer decoded stream based on the MIME 
+     * fields with the standard defaults.
+     * <p/>
+     * This method is valid, if {@link #getState()} returns either of
+     * {@link #T_RAW_ENTITY}, {@link #T_PREAMBLE}, or {@link #T_EPILOGUE}.
+     * 
+     * @return Data stream, depending on the current state.
+     * @throws IllegalStateException {@link #getState()} returns an
+     *   invalid value.
+     */
+    public InputStream getDecodedInputStream() {
+        BodyDescriptor bodyDescriptor = getBodyDescriptor();
+        String transferEncoding = bodyDescriptor.getTransferEncoding();
+        InputStream dataStream = currentStateMachine.getContentStream();
+        if (MimeUtil.isBase64Encoding(transferEncoding)) {
+            dataStream = new Base64InputStream(dataStream);
+        } else if (MimeUtil.isQuotedPrintableEncoded(transferEncoding)) {
+            dataStream = new QuotedPrintableInputStream(dataStream);
+        }
+        return dataStream;
+    }
+
+    /**
+     * Gets a reader configured for the current body or body part.
+     * The reader will return a transfer and charset decoded 
+     * stream of characters based on the MIME fields with the standard
+     * defaults.
+     * This is a conveniance method and relies on {@link #getInputStream()}.
+     * Consult the javadoc for that method for known limitations.
+     * 
+     * @return <code>Reader</code>, not null
+     * @see #getInputStream 
+     * @throws IllegalStateException {@link #getState()} returns an
+     *   invalid value 
+     * @throws UnsupportedCharsetException if there is no JVM support 
+     * for decoding the charset
+     * @throws IllegalCharsetNameException if the charset name specified
+     * in the mime type is illegal
+     */
+    public Reader getReader() {
+        final BodyDescriptor bodyDescriptor = getBodyDescriptor();
+        final String mimeCharset = bodyDescriptor.getCharset();
+        final Charset charset;
+        if (mimeCharset == null || "".equals(mimeCharset)) {
+            charset = CharsetUtil.US_ASCII;
+        } else {
+            charset = Charset.forName(mimeCharset);
+        }
+        final InputStream instream = getDecodedInputStream();
+        return new InputStreamReader(instream, charset);
+    }
+    
+    /**
+     * <p>Gets a descriptor for the current entity.
+     * This method is valid if {@link #getState()} returns:</p>
+     * <ul>
+     * <li>{@link #T_BODY}</li>
+     * <li>{@link #T_START_MULTIPART}</li>
+     * <li>{@link #T_EPILOGUE}</li>
+     * <li>{@link #T_PREAMBLE}</li>
+     * </ul>
+     * @return <code>BodyDescriptor</code>, not nulls
+     */
+    public BodyDescriptor getBodyDescriptor() {
+        return currentStateMachine.getBodyDescriptor();
+    }
+
+    /**
+     * This method is valid, if {@link #getState()} returns {@link #T_FIELD}.
+     * @return String with the fields raw contents.
+     * @throws IllegalStateException {@link #getState()} returns another
+     *   value than {@link #T_FIELD}.
+     */
+    public Field getField() {
+        return currentStateMachine.getField();
+    }
+    
+    /**
+     * This method advances the token stream to the next token.
+     * @throws IllegalStateException The method has been called, although
+     *   {@link #getState()} was already {@link #T_END_OF_STREAM}.
+     */
+    public int next() throws IOException, MimeException {
+        if (state == T_END_OF_STREAM  ||  currentStateMachine == null) {
+            throw new IllegalStateException("No more tokens are available.");
+        }
+        while (currentStateMachine != null) {
+            EntityStateMachine next = currentStateMachine.advance();
+            if (next != null) {
+                entities.add(next);
+                currentStateMachine = next;
+            }
+            state = currentStateMachine.getState();
+            if (state != T_END_OF_STREAM) {
+                return state;
+            }
+            entities.removeLast();
+            if (entities.isEmpty()) {
+                currentStateMachine = null;
+            } else {
+                currentStateMachine = entities.getLast();
+                currentStateMachine.setRecursionMode(recursionMode);
+            }
+        }
+        state = T_END_OF_STREAM;
+        return state;
+    }
+
+    /**
+     * Renders a state as a string suitable for logging.
+     * @param state 
+     * @return rendered as string, not null
+     */
+    public static final String stateToString(int state) {
+        return AbstractEntity.stateToString(state);
+    }
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RawEntity.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RawEntity.java
new file mode 100644
index 0000000..3a5f035
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RawEntity.java
@@ -0,0 +1,92 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+import org.apache.james.mime4j.descriptor.BodyDescriptor;

+

+import java.io.InputStream;

+

+/**

+ * Raw MIME entity. Such entities will not be parsed into elements 

+ * by the parser. They are meant to be consumed as a raw data stream

+ * by the caller.  

+ */

+public class RawEntity implements EntityStateMachine {

+

+    private final InputStream stream;

+

+    private int state;

+    

+    RawEntity(InputStream stream) {

+        this.stream = stream;

+        this.state = EntityStates.T_RAW_ENTITY;

+    }

+    

+    public int getState() {

+        return state;

+    }

+

+    /**

+     * This method has no effect.

+     */

+    public void setRecursionMode(int recursionMode) {

+    }

+

+    public EntityStateMachine advance() {

+        state = EntityStates.T_END_OF_STREAM;

+        return null;

+    }

+    

+    /**

+     * Returns raw data stream.

+     */

+    public InputStream getContentStream() {

+        return stream;

+    }

+

+    /**

+     * This method has no effect and always returns <code>null</code>.

+     */

+    public BodyDescriptor getBodyDescriptor() {

+        return null;

+    }

+

+    /**

+     * This method has no effect and always returns <code>null</code>.

+     */

+    public Field getField() {

+        return null;

+    }

+

+    /**

+     * This method has no effect and always returns <code>null</code>.

+     */

+    public String getFieldName() {

+        return null;

+    }

+

+    /**

+     * This method has no effect and always returns <code>null</code>.

+     */

+    public String getFieldValue() {

+        return null;

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RawField.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RawField.java
new file mode 100644
index 0000000..1ff672a
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RawField.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+
+/**
+ * The basic immutable MIME field.
+ */
+class RawField implements Field {
+
+    private final ByteSequence raw;
+    private int colonIdx;
+
+    private String name;
+    private String body;
+
+    public RawField(ByteSequence raw, int colonIdx) {
+        this.raw = raw;
+        this.colonIdx = colonIdx;
+    }
+
+    public String getName() {
+        if (name == null) {
+            name = parseName();
+        }
+
+        return name;
+    }
+
+    public String getBody() {
+        if (body == null) {
+            body = parseBody();
+        }
+
+        return body;
+    }
+
+    public ByteSequence getRaw() {
+        return raw;
+    }
+
+    @Override
+    public String toString() {
+        return getName() + ':' + getBody();
+    }
+
+    private String parseName() {
+        return ContentUtil.decode(raw, 0, colonIdx);
+    }
+
+    private String parseBody() {
+        int offset = colonIdx + 1;
+        int length = raw.length() - offset;
+        return ContentUtil.decode(raw, offset, length);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RecursionMode.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RecursionMode.java
new file mode 100644
index 0000000..9a25879
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/parser/RecursionMode.java
@@ -0,0 +1,45 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+/**

+ * Enumeration of parsing modes.

+ */

+public interface RecursionMode {

+

+    /** 

+     * Recursively parse every <code>message/rfc822</code> part 

+     */

+    int M_RECURSE = 0;

+    /**

+     * Do not recurse <code>message/rfc822</code> parts 

+     */

+    int M_NO_RECURSE = 1;

+    /** 

+     * Parse into raw entities

+     */

+    int M_RAW = 2;

+    /**

+     * Do not recurse <code>message/rfc822</code> parts

+     * and treat multiparts as a single flat body. 

+     */

+    int M_FLAT = 3;

+    

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/AbstractStorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/AbstractStorageProvider.java
new file mode 100644
index 0000000..c8046c4
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/AbstractStorageProvider.java
@@ -0,0 +1,61 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+
+/**
+ * Abstract implementation of {@link StorageProvider} that implements
+ * {@link StorageProvider#store(InputStream) store(InputStream)} by copying the
+ * input stream to a {@link StorageOutputStream} obtained from
+ * {@link StorageProvider#createStorageOutputStream() createStorageOutputStream()}.
+ */
+public abstract class AbstractStorageProvider implements StorageProvider {
+
+    /**
+     * Sole constructor.
+     */
+    protected AbstractStorageProvider() {
+    }
+
+    /**
+     * This implementation creates a {@link StorageOutputStream} by calling
+     * {@link StorageProvider#createStorageOutputStream() createStorageOutputStream()}
+     * and copies the content of the given input stream to that output stream.
+     * It then calls {@link StorageOutputStream#toStorage()} on the output
+     * stream and returns this object.
+     *
+     * @param in
+     *            stream containing the data to store.
+     * @return a {@link Storage} instance that can be used to retrieve the
+     *         stored content.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public final Storage store(InputStream in) throws IOException {
+        StorageOutputStream out = createStorageOutputStream();
+        CodecUtil.copy(in, out);
+        return out.toStorage();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/CipherStorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/CipherStorageProvider.java
new file mode 100644
index 0000000..24216c7
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/CipherStorageProvider.java
@@ -0,0 +1,177 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * A {@link StorageProvider} that transparently scrambles and unscrambles the
+ * data stored by another <code>StorageProvider</code>.
+ *
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ * StorageProvider mistrusted = new TempFileStorageProvider();
+ * StorageProvider enciphered = new CipherStorageProvider(mistrusted);
+ * StorageProvider provider = new ThresholdStorageProvider(enciphered);
+ * DefaultStorageProvider.setInstance(provider);
+ * </pre>
+ */
+public class CipherStorageProvider extends AbstractStorageProvider {
+
+    private final StorageProvider backend;
+    private final String algorithm;
+    private final KeyGenerator keygen;
+
+    /**
+     * Creates a new <code>CipherStorageProvider</code> for the given back-end
+     * using the Blowfish cipher algorithm.
+     *
+     * @param backend
+     *            back-end storage strategy to encrypt.
+     */
+    public CipherStorageProvider(StorageProvider backend) {
+        this(backend, "Blowfish");
+    }
+
+    /**
+     * Creates a new <code>CipherStorageProvider</code> for the given back-end
+     * and cipher algorithm.
+     *
+     * @param backend
+     *            back-end storage strategy to encrypt.
+     * @param algorithm
+     *            the name of the symmetric block cipher algorithm such as
+     *            "Blowfish", "AES" or "RC2".
+     */
+    public CipherStorageProvider(StorageProvider backend, String algorithm) {
+        if (backend == null)
+            throw new IllegalArgumentException();
+
+        try {
+            this.backend = backend;
+            this.algorithm = algorithm;
+            this.keygen = KeyGenerator.getInstance(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    public StorageOutputStream createStorageOutputStream() throws IOException {
+        SecretKeySpec skeySpec = getSecretKeySpec();
+
+        return new CipherStorageOutputStream(backend
+                .createStorageOutputStream(), algorithm, skeySpec);
+    }
+
+    private SecretKeySpec getSecretKeySpec() {
+        byte[] raw = keygen.generateKey().getEncoded();
+        return new SecretKeySpec(raw, algorithm);
+    }
+
+    private static final class CipherStorageOutputStream extends
+            StorageOutputStream {
+        private final StorageOutputStream storageOut;
+        private final String algorithm;
+        private final SecretKeySpec skeySpec;
+        private final CipherOutputStream cipherOut;
+
+        public CipherStorageOutputStream(StorageOutputStream out,
+                String algorithm, SecretKeySpec skeySpec) throws IOException {
+            try {
+                this.storageOut = out;
+                this.algorithm = algorithm;
+                this.skeySpec = skeySpec;
+
+                Cipher cipher = Cipher.getInstance(algorithm);
+                cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
+
+                this.cipherOut = new CipherOutputStream(out, cipher);
+            } catch (GeneralSecurityException e) {
+                throw (IOException) new IOException().initCause(e);
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+            cipherOut.close();
+        }
+
+        @Override
+        protected void write0(byte[] buffer, int offset, int length)
+                throws IOException {
+            cipherOut.write(buffer, offset, length);
+        }
+
+        @Override
+        protected Storage toStorage0() throws IOException {
+            // cipherOut has already been closed because toStorage calls close
+            Storage encrypted = storageOut.toStorage();
+            return new CipherStorage(encrypted, algorithm, skeySpec);
+        }
+    }
+
+    private static final class CipherStorage implements Storage {
+        private Storage encrypted;
+        private final String algorithm;
+        private final SecretKeySpec skeySpec;
+
+        public CipherStorage(Storage encrypted, String algorithm,
+                SecretKeySpec skeySpec) {
+            this.encrypted = encrypted;
+            this.algorithm = algorithm;
+            this.skeySpec = skeySpec;
+        }
+
+        public void delete() {
+            if (encrypted != null) {
+                encrypted.delete();
+                encrypted = null;
+            }
+        }
+
+        public InputStream getInputStream() throws IOException {
+            if (encrypted == null)
+                throw new IllegalStateException("storage has been deleted");
+
+            try {
+                Cipher cipher = Cipher.getInstance(algorithm);
+                cipher.init(Cipher.DECRYPT_MODE, skeySpec);
+
+                InputStream in = encrypted.getInputStream();
+                return new CipherInputStream(in, cipher);
+            } catch (GeneralSecurityException e) {
+                throw (IOException) new IOException().initCause(e);
+            }
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/DefaultStorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/DefaultStorageProvider.java
new file mode 100644
index 0000000..4af1c81
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/DefaultStorageProvider.java
@@ -0,0 +1,101 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Allows for a default {@link StorageProvider} instance to be configured on an
+ * application level.
+ * <p>
+ * The default instance can be set by either calling
+ * {@link #setInstance(StorageProvider)} when the application starts up or by
+ * setting the system property
+ * <code>org.apache.james.mime4j.defaultStorageProvider</code> to the class
+ * name of a <code>StorageProvider</code> implementation.
+ * <p>
+ * If neither option is used or if the class instantiation fails this class
+ * provides a pre-configured default instance.
+ */
+public class DefaultStorageProvider {
+
+    /** Value is <code>org.apache.james.mime4j.defaultStorageProvider</code> */
+    public static final String DEFAULT_STORAGE_PROVIDER_PROPERTY =
+        "org.apache.james.mime4j.defaultStorageProvider";
+
+    private static Log log = LogFactory.getLog(DefaultStorageProvider.class);
+
+    private static volatile StorageProvider instance = null;
+
+    static {
+        initialize();
+    }
+
+    private DefaultStorageProvider() {
+    }
+
+    /**
+     * Returns the default {@link StorageProvider} instance.
+     *
+     * @return the default {@link StorageProvider} instance.
+     */
+    public static StorageProvider getInstance() {
+        return instance;
+    }
+
+    /**
+     * Sets the default {@link StorageProvider} instance.
+     *
+     * @param instance
+     *            the default {@link StorageProvider} instance.
+     */
+    public static void setInstance(StorageProvider instance) {
+        if (instance == null) {
+            throw new IllegalArgumentException();
+        }
+
+        DefaultStorageProvider.instance = instance;
+    }
+
+    private static void initialize() {
+        String clazz = System.getProperty(DEFAULT_STORAGE_PROVIDER_PROPERTY);
+        try {
+            if (clazz != null) {
+                instance = (StorageProvider) Class.forName(clazz).newInstance();
+            }
+        } catch (Exception e) {
+            log.warn("Unable to create or instantiate StorageProvider class '"
+                    + clazz + "'. Using default instead.", e);
+        }
+
+        if (instance == null) {
+            StorageProvider backend = new TempFileStorageProvider();
+            instance = new ThresholdStorageProvider(backend, 1024);
+        }
+    }
+
+    // for unit tests only
+    static void reset() {
+        instance = null;
+        initialize();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/MemoryStorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/MemoryStorageProvider.java
new file mode 100644
index 0000000..d53e6c5
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/MemoryStorageProvider.java
@@ -0,0 +1,87 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+/**
+ * A {@link StorageProvider} that stores the data entirely in memory.
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ * StorageProvider provider = new MemoryStorageProvider();
+ * DefaultStorageProvider.setInstance(provider);
+ * </pre>
+ */
+public class MemoryStorageProvider extends AbstractStorageProvider {
+
+    /**
+     * Creates a new <code>MemoryStorageProvider</code>.
+     */
+    public MemoryStorageProvider() {
+    }
+
+    public StorageOutputStream createStorageOutputStream() {
+        return new MemoryStorageOutputStream();
+    }
+
+    private static final class MemoryStorageOutputStream extends
+            StorageOutputStream {
+        ByteArrayBuffer bab = new ByteArrayBuffer(1024);
+
+        @Override
+        protected void write0(byte[] buffer, int offset, int length)
+                throws IOException {
+            bab.append(buffer, offset, length);
+        }
+
+        @Override
+        protected Storage toStorage0() throws IOException {
+            return new MemoryStorage(bab.buffer(), bab.length());
+        }
+    }
+
+    static final class MemoryStorage implements Storage {
+        private byte[] data;
+        private final int count;
+
+        public MemoryStorage(byte[] data, int count) {
+            this.data = data;
+            this.count = count;
+        }
+
+        public InputStream getInputStream() throws IOException {
+            if (data == null)
+                throw new IllegalStateException("storage has been deleted");
+
+            return new ByteArrayInputStream(data, 0, count);
+        }
+
+        public void delete() {
+            data = null;
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/MultiReferenceStorage.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/MultiReferenceStorage.java
new file mode 100644
index 0000000..d239dfb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/MultiReferenceStorage.java
@@ -0,0 +1,131 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <p>
+ * A wrapper around another {@link Storage} that also maintains a reference
+ * counter. The inner storage gets deleted only if the reference counter reaches
+ * zero.
+ * </p>
+ * <p>
+ * Reference counting is used to delete the storage when it is no longer needed.
+ * So, any users of this class should note:
+ * </p>
+ * <ul>
+ * <li>The reference count is set up one on construction. In all other cases,
+ * {@link #addReference()} should be called when the storage is shared.</li>
+ * <li>The caller of {@link #addReference()} should ensure that
+ * {@link #delete()} is called once and only once.</li>
+ * <li>Sharing the {@link Storage} instance passed into
+ * {@link #MultiReferenceStorage(Storage)} may lead to miscounting and premature
+ * deletion</li>
+ * </ul>
+ */
+public class MultiReferenceStorage implements Storage {
+
+    private final Storage storage;
+    private int referenceCounter;
+
+    /**
+     * Creates a new <code>MultiReferenceStorage</code> instance for the given
+     * back-end. The reference counter is initially set to one so the caller
+     * does not have to call {@link #addReference()} after this constructor.
+     *
+     * @param storage
+     *            storage back-end that should be reference counted.
+     * @throws IllegalArgumentException
+     *             when storage is null
+     */
+    public MultiReferenceStorage(Storage storage) {
+        if (storage == null)
+            throw new IllegalArgumentException();
+
+        this.storage = storage;
+        this.referenceCounter = 1; // caller holds first reference
+    }
+
+    /**
+     * Increments the reference counter.
+     *
+     * @throws IllegalStateException
+     *             if the reference counter is zero which implies that the
+     *             backing storage has already been deleted.
+     */
+    public void addReference() {
+        incrementCounter();
+    }
+
+    /**
+     * Decrements the reference counter and deletes the inner
+     * <code>Storage</code> object if the reference counter reaches zero.
+     * <p>
+     * A client that holds a reference to this object must make sure not to
+     * invoke this method a second time.
+     *
+     * @throws IllegalStateException
+     *             if the reference counter is zero which implies that the
+     *             backing storage has already been deleted.
+     */
+    public void delete() {
+        if (decrementCounter()) {
+            storage.delete();
+        }
+    }
+
+    /**
+     * Returns the input stream of the inner <code>Storage</code> object.
+     *
+     * @return an input stream.
+     */
+    public InputStream getInputStream() throws IOException {
+        return storage.getInputStream();
+    }
+
+    /**
+     * Synchronized increment of reference count.
+     *
+     * @throws IllegalStateException
+     *             when counter is already zero
+     */
+    private synchronized void incrementCounter() {
+        if (referenceCounter == 0)
+            throw new IllegalStateException("storage has been deleted");
+
+        referenceCounter++;
+    }
+
+    /**
+     * Synchronized decrement of reference count.
+     *
+     * @return true when counter has reached zero, false otherwise
+     * @throws IllegalStateException
+     *             when counter is already zero
+     */
+    private synchronized boolean decrementCounter() {
+        if (referenceCounter == 0)
+            throw new IllegalStateException("storage has been deleted");
+
+        return --referenceCounter == 0;
+    }
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/Storage.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/Storage.java
new file mode 100644
index 0000000..0179d01
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/Storage.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Can be used to read data that has been stored by a {@link StorageProvider}.
+ */
+public interface Storage {
+    /**
+     * Returns an <code>InputStream</code> that can be used to read the stored
+     * data. The input stream should be closed by the caller when it is no
+     * longer needed.
+     * <p>
+     * Note: The stream should NOT be wrapped in a
+     * <code>BufferedInputStream</code> by the caller. If the implementing
+     * <code>Storage</code> creates a stream which would benefit from being
+     * buffered it is the <code>Storage</code>'s responsibility to wrap it.
+     *
+     * @return an <code>InputStream</code> for reading the stored data.
+     * @throws IOException
+     *             if an I/O error occurs.
+     * @throws IllegalStateException
+     *             if this <code>Storage</code> instance has been deleted.
+     */
+    InputStream getInputStream() throws IOException;
+
+    /**
+     * Deletes the data held by this <code>Storage</code> as soon as possible.
+     * Deleting an already deleted <code>Storage</code> has no effect.
+     */
+    void delete();
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/StorageOutputStream.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/StorageOutputStream.java
new file mode 100644
index 0000000..9e10459
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/StorageOutputStream.java
@@ -0,0 +1,170 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This class implements an output stream that can be used to create a
+ * {@link Storage} object. An instance of this class is obtained by calling
+ * {@link StorageProvider#createStorageOutputStream()}. The user can then write
+ * data to this instance and invoke {@link #toStorage()} to retrieve a
+ * {@link Storage} object that contains the data that has been written.
+ * <p>
+ * Note that the <code>StorageOutputStream</code> does not have to be closed
+ * explicitly because {@link #toStorage()} invokes {@link #close()} if
+ * necessary. Also note that {@link #toStorage()} may be invoked only once. One
+ * <code>StorageOutputStream</code> can create only one <code>Storage</code>
+ * instance.
+ */
+public abstract class StorageOutputStream extends OutputStream {
+
+    private byte[] singleByte;
+    private boolean closed;
+    private boolean usedUp;
+
+    /**
+     * Sole constructor.
+     */
+    protected StorageOutputStream() {
+    }
+
+    /**
+     * Closes this output stream if it has not already been closed and returns a
+     * {@link Storage} object which contains the bytes that have been written to
+     * this output stream.
+     * <p>
+     * Note that this method may not be invoked a second time. This is because
+     * for some implementations it is not possible to create another
+     * <code>Storage</code> object that can be read from and deleted
+     * independently (e.g. if the implementation writes to a file).
+     * 
+     * @return a <code>Storage</code> object as described above.
+     * @throws IOException
+     *             if an I/O error occurs.
+     * @throws IllegalStateException
+     *             if this method has already been called.
+     */
+    public final Storage toStorage() throws IOException {
+        if (usedUp)
+            throw new IllegalStateException(
+                    "toStorage may be invoked only once");
+
+        if (!closed)
+            close();
+
+        usedUp = true;
+        return toStorage0();
+    }
+
+    @Override
+    public final void write(int b) throws IOException {
+        if (closed)
+            throw new IOException("StorageOutputStream has been closed");
+
+        if (singleByte == null)
+            singleByte = new byte[1];
+
+        singleByte[0] = (byte) b;
+        write0(singleByte, 0, 1);
+    }
+
+    @Override
+    public final void write(byte[] buffer) throws IOException {
+        if (closed)
+            throw new IOException("StorageOutputStream has been closed");
+
+        if (buffer == null)
+            throw new NullPointerException();
+
+        if (buffer.length == 0)
+            return;
+
+        write0(buffer, 0, buffer.length);
+    }
+
+    @Override
+    public final void write(byte[] buffer, int offset, int length)
+            throws IOException {
+        if (closed)
+            throw new IOException("StorageOutputStream has been closed");
+
+        if (buffer == null)
+            throw new NullPointerException();
+
+        if (offset < 0 || length < 0 || offset + length > buffer.length)
+            throw new IndexOutOfBoundsException();
+
+        if (length == 0)
+            return;
+
+        write0(buffer, offset, length);
+    }
+
+    /**
+     * Closes this output stream. Subclasses that override this method have to
+     * invoke <code>super.close()</code>.
+     * <p>
+     * This implementation never throws an {@link IOException} but a subclass
+     * might.
+     * 
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    @Override
+    public void close() throws IOException {
+        closed = true;
+    }
+
+    /**
+     * Has to implemented by a concrete subclass to write bytes from the given
+     * byte array to this <code>StorageOutputStream</code>. This method gets
+     * called by {@link #write(int)}, {@link #write(byte[])} and
+     * {@link #write(byte[], int, int)}. All the required preconditions have
+     * already been checked by these methods, including the check if the output
+     * stream has already been closed.
+     * 
+     * @param buffer
+     *            buffer containing bytes to write.
+     * @param offset
+     *            start offset in the buffer.
+     * @param length
+     *            number of bytes to write.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    protected abstract void write0(byte[] buffer, int offset, int length)
+            throws IOException;
+
+    /**
+     * Has to be implemented by a concrete subclass to create a {@link Storage}
+     * object from the bytes that have been written to this
+     * <code>StorageOutputStream</code>. This method gets called by
+     * {@link #toStorage()} after the preconditions have been checked. The
+     * implementation can also be sure that this methods gets invoked only once.
+     * 
+     * @return a <code>Storage</code> object as described above.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    protected abstract Storage toStorage0() throws IOException;
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/StorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/StorageProvider.java
new file mode 100644
index 0000000..5a6c89e
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/StorageProvider.java
@@ -0,0 +1,51 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provides a strategy for storing the contents of an <code>InputStream</code>
+ * or retrieving the content written to an <code>OutputStream</code>.
+ */
+public interface StorageProvider {
+    /**
+     * Stores the contents of the given <code>InputStream</code>.
+     *
+     * @param in stream containing the data to store.
+     * @return a {@link Storage} instance that can be used to retrieve the
+     *         stored content.
+     * @throws IOException if an I/O error occurs.
+     */
+    Storage store(InputStream in) throws IOException;
+
+    /**
+     * Creates a {@link StorageOutputStream} where data to be stored can be
+     * written to. Subsequently the user can call
+     * {@link StorageOutputStream#toStorage() toStorage()} on that object to get
+     * a {@link Storage} instance that holds the data that has been written.
+     *
+     * @return a {@link StorageOutputStream} where data can be written to.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    StorageOutputStream createStorageOutputStream() throws IOException;
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/TempFileStorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/TempFileStorageProvider.java
new file mode 100644
index 0000000..6c30acb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/TempFileStorageProvider.java
@@ -0,0 +1,183 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A {@link StorageProvider} that stores the data in temporary files. The files
+ * are stored either in a user-specified directory or the default temporary-file
+ * directory (specified by system property <code>java.io.tmpdir</code>).
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ * File directory = new File(&quot;/tmp/mime4j&quot;);
+ * StorageProvider provider = new TempFileStorageProvider(directory);
+ * DefaultStorageProvider.setInstance(provider);
+ * </pre>
+ */
+public class TempFileStorageProvider extends AbstractStorageProvider {
+
+    private static final String DEFAULT_PREFIX = "m4j";
+
+    private final String prefix;
+    private final String suffix;
+    private final File directory;
+
+    /**
+     * Equivalent to using constructor
+     * <code>TempFileStorageProvider("m4j", null, null)</code>.
+     */
+    public TempFileStorageProvider() {
+        this(DEFAULT_PREFIX, null, null);
+    }
+
+    /**
+     * Equivalent to using constructor
+     * <code>TempFileStorageProvider("m4j", null, directory)</code>.
+     */
+    public TempFileStorageProvider(File directory) {
+        this(DEFAULT_PREFIX, null, directory);
+    }
+
+    /**
+     * Creates a new <code>TempFileStorageProvider</code> using the given
+     * values.
+     *
+     * @param prefix
+     *            prefix for generating the temporary file's name; must be at
+     *            least three characters long.
+     * @param suffix
+     *            suffix for generating the temporary file's name; may be
+     *            <code>null</code> to use the suffix <code>".tmp"</code>.
+     * @param directory
+     *            the directory in which the file is to be created, or
+     *            <code>null</code> if the default temporary-file directory is
+     *            to be used (specified by the system property
+     *            <code>java.io.tmpdir</code>).
+     * @throws IllegalArgumentException
+     *             if the given prefix is less than three characters long or the
+     *             given directory does not exist and cannot be created (if it
+     *             is not <code>null</code>).
+     */
+    public TempFileStorageProvider(String prefix, String suffix, File directory) {
+        if (prefix == null || prefix.length() < 3)
+            throw new IllegalArgumentException("invalid prefix");
+
+        if (directory != null && !directory.isDirectory()
+                && !directory.mkdirs())
+            throw new IllegalArgumentException("invalid directory");
+
+        this.prefix = prefix;
+        this.suffix = suffix;
+        this.directory = directory;
+    }
+
+    public StorageOutputStream createStorageOutputStream() throws IOException {
+        File file = File.createTempFile(prefix, suffix, directory);
+        file.deleteOnExit();
+
+        return new TempFileStorageOutputStream(file);
+    }
+
+    private static final class TempFileStorageOutputStream extends
+            StorageOutputStream {
+        private File file;
+        private OutputStream out;
+
+        public TempFileStorageOutputStream(File file) throws IOException {
+            this.file = file;
+            this.out = new FileOutputStream(file);
+        }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+            out.close();
+        }
+
+        @Override
+        protected void write0(byte[] buffer, int offset, int length)
+                throws IOException {
+            out.write(buffer, offset, length);
+        }
+
+        @Override
+        protected Storage toStorage0() throws IOException {
+            // out has already been closed because toStorage calls close
+            return new TempFileStorage(file);
+        }
+    }
+
+    private static final class TempFileStorage implements Storage {
+
+        private File file;
+
+        private static final Set<File> filesToDelete = new HashSet<File>();
+
+        public TempFileStorage(File file) {
+            this.file = file;
+        }
+
+        public void delete() {
+            // deleting a file might not immediately succeed if there are still
+            // streams left open (especially under Windows). so we keep track of
+            // the files that have to be deleted and try to delete all these
+            // files each time this method gets invoked.
+
+            // a better but more complicated solution would be to start a
+            // separate thread that tries to delete the files periodically.
+
+            synchronized (filesToDelete) {
+                if (file != null) {
+                    filesToDelete.add(file);
+                    file = null;
+                }
+
+                for (Iterator<File> iterator = filesToDelete.iterator(); iterator
+                        .hasNext();) {
+                    File file = iterator.next();
+                    if (file.delete()) {
+                        iterator.remove();
+                    }
+                }
+            }
+        }
+
+        public InputStream getInputStream() throws IOException {
+            if (file == null)
+                throw new IllegalStateException("storage has been deleted");
+
+            return new BufferedInputStream(new FileInputStream(file));
+        }
+
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/ThresholdStorageProvider.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/ThresholdStorageProvider.java
new file mode 100644
index 0000000..32ad992
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/storage/ThresholdStorageProvider.java
@@ -0,0 +1,161 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.SequenceInputStream;
+
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+/**
+ * A {@link StorageProvider} that keeps small amounts of data in memory and
+ * writes the remainder to another <code>StorageProvider</code> (the back-end)
+ * if a certain threshold size gets exceeded.
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ * StorageProvider tempStore = new TempFileStorageProvider();
+ * StorageProvider provider = new ThresholdStorageProvider(tempStore, 4096);
+ * DefaultStorageProvider.setInstance(provider);
+ * </pre>
+ */
+public class ThresholdStorageProvider extends AbstractStorageProvider {
+
+    private final StorageProvider backend;
+    private final int thresholdSize;
+
+    /**
+     * Creates a new <code>ThresholdStorageProvider</code> for the given
+     * back-end using a threshold size of 2048 bytes.
+     */
+    public ThresholdStorageProvider(StorageProvider backend) {
+        this(backend, 2048);
+    }
+
+    /**
+     * Creates a new <code>ThresholdStorageProvider</code> for the given
+     * back-end and threshold size.
+     *
+     * @param backend
+     *            used to store the remainder of the data if the threshold size
+     *            gets exceeded.
+     * @param thresholdSize
+     *            determines how much bytes are kept in memory before that
+     *            back-end storage provider is used to store the remainder of
+     *            the data.
+     */
+    public ThresholdStorageProvider(StorageProvider backend, int thresholdSize) {
+        if (backend == null)
+            throw new IllegalArgumentException();
+        if (thresholdSize < 1)
+            throw new IllegalArgumentException();
+
+        this.backend = backend;
+        this.thresholdSize = thresholdSize;
+    }
+
+    public StorageOutputStream createStorageOutputStream() {
+        return new ThresholdStorageOutputStream();
+    }
+
+    private final class ThresholdStorageOutputStream extends
+            StorageOutputStream {
+
+        private final ByteArrayBuffer head;
+        private StorageOutputStream tail;
+
+        public ThresholdStorageOutputStream() {
+            final int bufferSize = Math.min(thresholdSize, 1024);
+            head = new ByteArrayBuffer(bufferSize);
+        }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+
+            if (tail != null)
+                tail.close();
+        }
+
+        @Override
+        protected void write0(byte[] buffer, int offset, int length)
+                throws IOException {
+            int remainingHeadSize = thresholdSize - head.length();
+            if (remainingHeadSize > 0) {
+                int n = Math.min(remainingHeadSize, length);
+                head.append(buffer, offset, n);
+                offset += n;
+                length -= n;
+            }
+
+            if (length > 0) {
+                if (tail == null)
+                    tail = backend.createStorageOutputStream();
+
+                tail.write(buffer, offset, length);
+            }
+        }
+
+        @Override
+        protected Storage toStorage0() throws IOException {
+            if (tail == null)
+                return new MemoryStorageProvider.MemoryStorage(head.buffer(),
+                        head.length());
+
+            return new ThresholdStorage(head.buffer(), head.length(), tail
+                    .toStorage());
+        }
+
+    }
+
+    private static final class ThresholdStorage implements Storage {
+
+        private byte[] head;
+        private final int headLen;
+        private Storage tail;
+
+        public ThresholdStorage(byte[] head, int headLen, Storage tail) {
+            this.head = head;
+            this.headLen = headLen;
+            this.tail = tail;
+        }
+
+        public void delete() {
+            if (head != null) {
+                head = null;
+                tail.delete();
+                tail = null;
+            }
+        }
+
+        public InputStream getInputStream() throws IOException {
+            if (head == null)
+                throw new IllegalStateException("storage has been deleted");
+
+            InputStream headStream = new ByteArrayInputStream(head, 0, headLen);
+            InputStream tailStream = tail.getInputStream();
+            return new SequenceInputStream(headStream, tailStream);
+        }
+
+    }
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ByteArrayBuffer.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ByteArrayBuffer.java
new file mode 100644
index 0000000..fb25900
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ByteArrayBuffer.java
@@ -0,0 +1,166 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+
+/**
+ * A resizable byte array.
+ */
+public final class ByteArrayBuffer implements ByteSequence {
+    
+    private byte[] buffer;
+    private int len;
+
+    public ByteArrayBuffer(int capacity) {
+        super();
+        if (capacity < 0) {
+            throw new IllegalArgumentException("Buffer capacity may not be negative");
+        }
+        this.buffer = new byte[capacity]; 
+    }
+
+    public ByteArrayBuffer(byte[] bytes, boolean dontCopy) {
+        this(bytes, bytes.length, dontCopy);
+    }
+    
+    public ByteArrayBuffer(byte[] bytes, int len, boolean dontCopy) {
+        if (bytes == null)
+            throw new IllegalArgumentException();
+        if (len < 0 || len > bytes.length)
+            throw new IllegalArgumentException();
+
+        if (dontCopy) {
+            this.buffer = bytes;
+        } else {
+            this.buffer = new byte[len];
+            System.arraycopy(bytes, 0, this.buffer, 0, len);
+        }
+
+        this.len = len;
+    }
+
+    private void expand(int newlen) {
+        byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
+        System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
+        this.buffer = newbuffer;
+    }
+    
+    public void append(final byte[] b, int off, int len) {
+        if (b == null) {
+            return;
+        }
+        if ((off < 0) || (off > b.length) || (len < 0) ||
+                ((off + len) < 0) || ((off + len) > b.length)) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (len == 0) {
+            return;
+        }
+        int newlen = this.len + len;
+        if (newlen > this.buffer.length) {
+            expand(newlen);
+        }
+        System.arraycopy(b, off, this.buffer, this.len, len);
+        this.len = newlen;
+    }
+
+    public void append(int b) {
+        int newlen = this.len + 1;
+        if (newlen > this.buffer.length) {
+            expand(newlen);
+        }
+        this.buffer[this.len] = (byte)b;
+        this.len = newlen;
+    }
+
+    public void clear() {
+        this.len = 0;
+    }
+    
+    public byte[] toByteArray() {
+        byte[] b = new byte[this.len]; 
+        if (this.len > 0) {
+            System.arraycopy(this.buffer, 0, b, 0, this.len);
+        }
+        return b;
+    }
+    
+    public byte byteAt(int i) {
+        if (i < 0 || i >= this.len)
+            throw new IndexOutOfBoundsException();
+
+        return this.buffer[i];
+    }
+    
+    public int capacity() {
+        return this.buffer.length;
+    }
+    
+    public int length() {
+        return this.len;
+    }
+
+    public byte[] buffer() {
+        return this.buffer;
+    }
+
+    public int indexOf(byte b) {
+        return indexOf(b, 0, this.len);
+    }
+
+    public int indexOf(byte b, int beginIndex, int endIndex) {
+        if (beginIndex < 0) {
+            beginIndex = 0;
+        }
+        if (endIndex > this.len) {
+            endIndex = this.len;
+        }
+        if (beginIndex > endIndex) {
+            return -1;
+        }
+        for (int i = beginIndex; i < endIndex; i++) {
+            if (this.buffer[i] == b) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public void setLength(int len) {
+        if (len < 0 || len > this.buffer.length) {
+            throw new IndexOutOfBoundsException();
+        }
+        this.len = len;
+    }
+    
+    public boolean isEmpty() {
+        return this.len == 0; 
+    }
+    
+    public boolean isFull() {
+        return this.len == this.buffer.length; 
+    }
+
+    @Override
+    public String toString() {
+        return new String(toByteArray());
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ByteSequence.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ByteSequence.java
new file mode 100644
index 0000000..c7c89d7
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ByteSequence.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+/**
+ * An immutable sequence of bytes.
+ */
+public interface ByteSequence {
+
+    /**
+     * An empty byte sequence.
+     */
+    ByteSequence EMPTY = new EmptyByteSequence();
+
+    /**
+     * Returns the length of this byte sequence.
+     * 
+     * @return the number of <code>byte</code>s in this sequence.
+     */
+    int length();
+
+    /**
+     * Returns the <code>byte</code> value at the specified index.
+     * 
+     * @param index
+     *            the index of the <code>byte</code> value to be returned.
+     * @return the corresponding <code>byte</code> value
+     * @throws IndexOutOfBoundsException
+     *             if <code>index < 0 || index >= length()</code>.
+     */
+    byte byteAt(int index);
+
+    /**
+     * Copies the contents of this byte sequence into a newly allocated byte
+     * array and returns that array.
+     * 
+     * @return a byte array holding a copy of this byte sequence.
+     */
+    byte[] toByteArray();
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/CharsetUtil.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/CharsetUtil.java
new file mode 100644
index 0000000..6aed7bc
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/CharsetUtil.java
@@ -0,0 +1,1271 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.util;

+

+import java.io.UnsupportedEncodingException;

+import java.nio.charset.IllegalCharsetNameException;

+import java.nio.charset.UnsupportedCharsetException;

+import java.util.HashMap;

+import java.util.Map;

+import java.util.SortedSet;

+import java.util.TreeSet;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+

+/**

+ * Utility class for working with character sets. It is somewhat similar to

+ * the Java 1.4 <code>java.nio.charset.Charset</code> class but knows many

+ * more aliases and is compatible with Java 1.3. It will use a simple detection

+ * mechanism to detect what character sets the current VM supports. This will

+ * be a sub-set of the character sets listed in the

+ * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">

+ * Java 1.5 (J2SE5.0) Supported Encodings</a> document.

+ * <p>

+ * The <a href="http://www.iana.org/assignments/character-sets">

+ * IANA Character Sets</a> document has been used to determine the preferred

+ * MIME character set names and to get a list of known aliases.

+ * <p>

+ * This is a complete list of the character sets known to this class:

+ * <table>

+ *     <tr>

+ *         <td>Canonical (Java) name</td>

+ *         <td>MIME preferred</td>

+ *         <td>Aliases</td>

+ *     </tr>

+ *     <tr>

+ *         <td>ASCII</td>

+ *         <td>US-ASCII</td>

+ *         <td>ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ISO646-US us IBM367 cp367 csASCII ascii7 646 iso_646.irv:1983 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Big5</td>

+ *         <td>Big5</td>

+ *         <td>csBig5 CN-Big5 BIG-FIVE BIGFIVE </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Big5_HKSCS</td>

+ *         <td>Big5-HKSCS</td>

+ *         <td>big5hkscs </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Big5_Solaris</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp037</td>

+ *         <td>IBM037</td>

+ *         <td>ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl csIBM037 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1006</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1025</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1026</td>

+ *         <td>IBM1026</td>

+ *         <td>csIBM1026 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1046</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1047</td>

+ *         <td>IBM1047</td>

+ *         <td>IBM-1047 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1097</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1098</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1112</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1122</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1123</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1124</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1140</td>

+ *         <td>IBM01140</td>

+ *         <td>CCSID01140 CP01140 ebcdic-us-37+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1141</td>

+ *         <td>IBM01141</td>

+ *         <td>CCSID01141 CP01141 ebcdic-de-273+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1142</td>

+ *         <td>IBM01142</td>

+ *         <td>CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1143</td>

+ *         <td>IBM01143</td>

+ *         <td>CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1144</td>

+ *         <td>IBM01144</td>

+ *         <td>CCSID01144 CP01144 ebcdic-it-280+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1145</td>

+ *         <td>IBM01145</td>

+ *         <td>CCSID01145 CP01145 ebcdic-es-284+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1146</td>

+ *         <td>IBM01146</td>

+ *         <td>CCSID01146 CP01146 ebcdic-gb-285+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1147</td>

+ *         <td>IBM01147</td>

+ *         <td>CCSID01147 CP01147 ebcdic-fr-297+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1148</td>

+ *         <td>IBM01148</td>

+ *         <td>CCSID01148 CP01148 ebcdic-international-500+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1149</td>

+ *         <td>IBM01149</td>

+ *         <td>CCSID01149 CP01149 ebcdic-is-871+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1250</td>

+ *         <td>windows-1250</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1251</td>

+ *         <td>windows-1251</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1252</td>

+ *         <td>windows-1252</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1253</td>

+ *         <td>windows-1253</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1254</td>

+ *         <td>windows-1254</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1255</td>

+ *         <td>windows-1255</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1256</td>

+ *         <td>windows-1256</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1257</td>

+ *         <td>windows-1257</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1258</td>

+ *         <td>windows-1258</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1381</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp1383</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp273</td>

+ *         <td>IBM273</td>

+ *         <td>csIBM273 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp277</td>

+ *         <td>IBM277</td>

+ *         <td>EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp278</td>

+ *         <td>IBM278</td>

+ *         <td>CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp280</td>

+ *         <td>IBM280</td>

+ *         <td>ebcdic-cp-it csIBM280 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp284</td>

+ *         <td>IBM284</td>

+ *         <td>ebcdic-cp-es csIBM284 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp285</td>

+ *         <td>IBM285</td>

+ *         <td>ebcdic-cp-gb csIBM285 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp297</td>

+ *         <td>IBM297</td>

+ *         <td>ebcdic-cp-fr csIBM297 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp33722</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp420</td>

+ *         <td>IBM420</td>

+ *         <td>ebcdic-cp-ar1 csIBM420 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp424</td>

+ *         <td>IBM424</td>

+ *         <td>ebcdic-cp-he csIBM424 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp437</td>

+ *         <td>IBM437</td>

+ *         <td>437 csPC8CodePage437 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp500</td>

+ *         <td>IBM500</td>

+ *         <td>ebcdic-cp-be ebcdic-cp-ch csIBM500 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp737</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp775</td>

+ *         <td>IBM775</td>

+ *         <td>csPC775Baltic </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp838</td>

+ *         <td>IBM-Thai</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp850</td>

+ *         <td>IBM850</td>

+ *         <td>850 csPC850Multilingual </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp852</td>

+ *         <td>IBM852</td>

+ *         <td>852 csPCp852 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp855</td>

+ *         <td>IBM855</td>

+ *         <td>855 csIBM855 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp856</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp857</td>

+ *         <td>IBM857</td>

+ *         <td>857 csIBM857 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp858</td>

+ *         <td>IBM00858</td>

+ *         <td>CCSID00858 CP00858 PC-Multilingual-850+euro </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp860</td>

+ *         <td>IBM860</td>

+ *         <td>860 csIBM860 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp861</td>

+ *         <td>IBM861</td>

+ *         <td>861 cp-is csIBM861 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp862</td>

+ *         <td>IBM862</td>

+ *         <td>862 csPC862LatinHebrew </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp863</td>

+ *         <td>IBM863</td>

+ *         <td>863 csIBM863 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp864</td>

+ *         <td>IBM864</td>

+ *         <td>cp864 csIBM864 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp865</td>

+ *         <td>IBM865</td>

+ *         <td>865 csIBM865 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp866</td>

+ *         <td>IBM866</td>

+ *         <td>866 csIBM866 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp868</td>

+ *         <td>IBM868</td>

+ *         <td>cp-ar csIBM868 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp869</td>

+ *         <td>IBM869</td>

+ *         <td>cp-gr csIBM869 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp870</td>

+ *         <td>IBM870</td>

+ *         <td>ebcdic-cp-roece ebcdic-cp-yu csIBM870 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp871</td>

+ *         <td>IBM871</td>

+ *         <td>ebcdic-cp-is csIBM871 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp875</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp918</td>

+ *         <td>IBM918</td>

+ *         <td>ebcdic-cp-ar2 csIBM918 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp921</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp922</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp930</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp933</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp935</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp937</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp939</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp942</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp942C</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp943</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp943C</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp948</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp949</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp949C</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp950</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp964</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>Cp970</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>EUC_CN</td>

+ *         <td>GB2312</td>

+ *         <td>x-EUC-CN csGB2312 euccn euc-cn gb2312-80 gb2312-1980 CN-GB CN-GB-ISOIR165 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>EUC_JP</td>

+ *         <td>EUC-JP</td>

+ *         <td>csEUCPkdFmtJapanese Extended_UNIX_Code_Packed_Format_for_Japanese eucjis x-eucjp eucjp x-euc-jp </td>

+ *     </tr>

+ *     <tr>

+ *         <td>EUC_JP_LINUX</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>EUC_JP_Solaris</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>EUC_KR</td>

+ *         <td>EUC-KR</td>

+ *         <td>csEUCKR ksc5601 5601 ksc5601_1987 ksc_5601 ksc5601-1987 ks_c_5601-1987 euckr </td>

+ *     </tr>

+ *     <tr>

+ *         <td>EUC_TW</td>

+ *         <td>EUC-TW</td>

+ *         <td>x-EUC-TW cns11643 euctw </td>

+ *     </tr>

+ *     <tr>

+ *         <td>GB18030</td>

+ *         <td>GB18030</td>

+ *         <td>gb18030-2000 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>GBK</td>

+ *         <td>windows-936</td>

+ *         <td>CP936 MS936 ms_936 x-mswin-936 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISCII91</td>

+ *         <td>?</td>

+ *         <td>x-ISCII91 iscii </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO2022CN</td>

+ *         <td>ISO-2022-CN</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO2022JP</td>

+ *         <td>ISO-2022-JP</td>

+ *         <td>csISO2022JP JIS jis_encoding csjisencoding </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO2022KR</td>

+ *         <td>ISO-2022-KR</td>

+ *         <td>csISO2022KR </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO2022_CN_CNS</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO2022_CN_GB</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_1</td>

+ *         <td>ISO-8859-1</td>

+ *         <td>ISO_8859-1:1987 iso-ir-100 ISO_8859-1 latin1 l1 IBM819 CP819 csISOLatin1 8859_1 819 IBM-819 ISO8859-1 ISO_8859_1 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_13</td>

+ *         <td>ISO-8859-13</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_15</td>

+ *         <td>ISO-8859-15</td>

+ *         <td>ISO_8859-15 Latin-9 8859_15 csISOlatin9 IBM923 cp923 923 L9 IBM-923 ISO8859-15 LATIN9 LATIN0 csISOlatin0 ISO8859_15_FDIS </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_2</td>

+ *         <td>ISO-8859-2</td>

+ *         <td>ISO_8859-2:1987 iso-ir-101 ISO_8859-2 latin2 l2 csISOLatin2 8859_2 iso8859_2 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_3</td>

+ *         <td>ISO-8859-3</td>

+ *         <td>ISO_8859-3:1988 iso-ir-109 ISO_8859-3 latin3 l3 csISOLatin3 8859_3 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_4</td>

+ *         <td>ISO-8859-4</td>

+ *         <td>ISO_8859-4:1988 iso-ir-110 ISO_8859-4 latin4 l4 csISOLatin4 8859_4 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_5</td>

+ *         <td>ISO-8859-5</td>

+ *         <td>ISO_8859-5:1988 iso-ir-144 ISO_8859-5 cyrillic csISOLatinCyrillic 8859_5 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_6</td>

+ *         <td>ISO-8859-6</td>

+ *         <td>ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ECMA-114 ASMO-708 arabic csISOLatinArabic 8859_6 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_7</td>

+ *         <td>ISO-8859-7</td>

+ *         <td>ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ELOT_928 ECMA-118 greek greek8 csISOLatinGreek 8859_7 sun_eu_greek </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_8</td>

+ *         <td>ISO-8859-8</td>

+ *         <td>ISO_8859-8:1988 iso-ir-138 ISO_8859-8 hebrew csISOLatinHebrew 8859_8 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>ISO8859_9</td>

+ *         <td>ISO-8859-9</td>

+ *         <td>ISO_8859-9:1989 iso-ir-148 ISO_8859-9 latin5 l5 csISOLatin5 8859_9 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>JISAutoDetect</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>JIS_C6626-1983</td>

+ *         <td>JIS_C6626-1983</td>

+ *         <td>x-JIS0208 JIS0208 csISO87JISX0208 x0208 JIS_X0208-1983 iso-ir-87 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>JIS_X0201</td>

+ *         <td>JIS_X0201</td>

+ *         <td>X0201 JIS0201 csHalfWidthKatakana </td>

+ *     </tr>

+ *     <tr>

+ *         <td>JIS_X0212-1990</td>

+ *         <td>JIS_X0212-1990</td>

+ *         <td>iso-ir-159 x0212 JIS0212 csISO159JISX02121990 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>KOI8_R</td>

+ *         <td>KOI8-R</td>

+ *         <td>csKOI8R koi8 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>MS874</td>

+ *         <td>windows-874</td>

+ *         <td>cp874 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>MS932</td>

+ *         <td>Windows-31J</td>

+ *         <td>windows-932 csWindows31J x-ms-cp932 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>MS949</td>

+ *         <td>windows-949</td>

+ *         <td>windows949 ms_949 x-windows-949 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>MS950</td>

+ *         <td>windows-950</td>

+ *         <td>x-windows-950 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>MS950_HKSCS</td>

+ *         <td></td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacArabic</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacCentralEurope</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacCroatian</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacCyrillic</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacDingbat</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacGreek</td>

+ *         <td>MacGreek</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacHebrew</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacIceland</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacRoman</td>

+ *         <td>MacRoman</td>

+ *         <td>Macintosh MAC csMacintosh </td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacRomania</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacSymbol</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacThai</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacTurkish</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>MacUkraine</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>SJIS</td>

+ *         <td>Shift_JIS</td>

+ *         <td>MS_Kanji csShiftJIS shift-jis x-sjis pck </td>

+ *     </tr>

+ *     <tr>

+ *         <td>TIS620</td>

+ *         <td>TIS-620</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>UTF-16</td>

+ *         <td>UTF-16</td>

+ *         <td>UTF_16 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>UTF8</td>

+ *         <td>UTF-8</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>UnicodeBig</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>UnicodeBigUnmarked</td>

+ *         <td>UTF-16BE</td>

+ *         <td>X-UTF-16BE UTF_16BE ISO-10646-UCS-2 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>UnicodeLittle</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ *     <tr>

+ *         <td>UnicodeLittleUnmarked</td>

+ *         <td>UTF-16LE</td>

+ *         <td>UTF_16LE X-UTF-16LE </td>

+ *     </tr>

+ *     <tr>

+ *         <td>x-Johab</td>

+ *         <td>johab</td>

+ *         <td>johab cp1361 ms1361 ksc5601-1992 ksc5601_1992 </td>

+ *     </tr>

+ *     <tr>

+ *         <td>x-iso-8859-11</td>

+ *         <td>?</td>

+ *         <td></td>

+ *     </tr>

+ * </table>

+ */

+public class CharsetUtil {

+    private static Log log = LogFactory.getLog(CharsetUtil.class);

+    

+    private static class Charset implements Comparable<Charset> {

+        private String canonical = null;

+        private String mime = null;

+        private String[] aliases = null;

+        

+        private Charset(String canonical, String mime, String[] aliases) {

+            this.canonical = canonical;

+            this.mime = mime;

+            this.aliases = aliases;

+        }

+

+        public int compareTo(Charset c) {

+            return this.canonical.compareTo(c.canonical);

+        }

+    }

+    

+    private static Charset[] JAVA_CHARSETS = {

+        new Charset("ISO8859_1", "ISO-8859-1", 

+                    new String[] {"ISO_8859-1:1987", "iso-ir-100", "ISO_8859-1", 

+                                  "latin1", "l1", "IBM819", "CP819", 

+                                  "csISOLatin1", "8859_1", "819", "IBM-819", 

+                                  "ISO8859-1", "ISO_8859_1"}),

+        new Charset("ISO8859_2", "ISO-8859-2", 

+                    new String[] {"ISO_8859-2:1987", "iso-ir-101", "ISO_8859-2",  

+                                  "latin2", "l2", "csISOLatin2", "8859_2", 

+                                  "iso8859_2"}),

+        new Charset("ISO8859_3", "ISO-8859-3", new String[] {"ISO_8859-3:1988", "iso-ir-109", "ISO_8859-3", "latin3", "l3", "csISOLatin3", "8859_3"}),

+        new Charset("ISO8859_4", "ISO-8859-4", 

+                    new String[] {"ISO_8859-4:1988", "iso-ir-110", "ISO_8859-4",

+                                  "latin4", "l4", "csISOLatin4", "8859_4"}),

+        new Charset("ISO8859_5", "ISO-8859-5", 

+                    new String[] {"ISO_8859-5:1988", "iso-ir-144", "ISO_8859-5", 

+                                  "cyrillic", "csISOLatinCyrillic", "8859_5"}),

+        new Charset("ISO8859_6", "ISO-8859-6", new String[] {"ISO_8859-6:1987", "iso-ir-127", "ISO_8859-6", "ECMA-114", "ASMO-708", "arabic", "csISOLatinArabic", "8859_6"}),

+        new Charset("ISO8859_7", "ISO-8859-7", 

+                    new String[] {"ISO_8859-7:1987", "iso-ir-126", "ISO_8859-7", 

+                                  "ELOT_928", "ECMA-118", "greek", "greek8", 

+                                  "csISOLatinGreek", "8859_7", "sun_eu_greek"}),

+        new Charset("ISO8859_8", "ISO-8859-8", new String[] {"ISO_8859-8:1988", "iso-ir-138", "ISO_8859-8", "hebrew", "csISOLatinHebrew", "8859_8"}),

+        new Charset("ISO8859_9", "ISO-8859-9", 

+                    new String[] {"ISO_8859-9:1989", "iso-ir-148", "ISO_8859-9",  

+                                  "latin5", "l5", "csISOLatin5", "8859_9"}),

+

+        new Charset("ISO8859_13", "ISO-8859-13", new String[] {}),

+        new Charset("ISO8859_15", "ISO-8859-15", 

+                    new String[] {"ISO_8859-15", "Latin-9", "8859_15", 

+                                  "csISOlatin9", "IBM923", "cp923", "923", "L9",

+                                  "IBM-923", "ISO8859-15", "LATIN9", "LATIN0", 

+                                  "csISOlatin0", "ISO8859_15_FDIS"}),

+        new Charset("KOI8_R", "KOI8-R", new String[] {"csKOI8R", "koi8"}),

+        new Charset("ASCII", "US-ASCII", 

+                    new String[] {"ANSI_X3.4-1968", "iso-ir-6", 

+                                  "ANSI_X3.4-1986", "ISO_646.irv:1991", 

+                                  "ISO646-US", "us", "IBM367", "cp367", 

+                                  "csASCII", "ascii7", "646", "iso_646.irv:1983"}),

+        new Charset("UTF8", "UTF-8", new String[] {}),

+        new Charset("UTF-16", "UTF-16", new String[] {"UTF_16"}),

+        new Charset("UnicodeBigUnmarked", "UTF-16BE", new String[] {"X-UTF-16BE", "UTF_16BE", "ISO-10646-UCS-2"}),

+        new Charset("UnicodeLittleUnmarked", "UTF-16LE", new String[] {"UTF_16LE", "X-UTF-16LE"}),

+        new Charset("Big5", "Big5", new String[] {"csBig5", "CN-Big5", "BIG-FIVE", "BIGFIVE"}),

+        new Charset("Big5_HKSCS", "Big5-HKSCS", new String[] {"big5hkscs"}),

+        new Charset("EUC_JP", "EUC-JP", 

+                    new String[] {"csEUCPkdFmtJapanese", 

+                              "Extended_UNIX_Code_Packed_Format_for_Japanese",

+                              "eucjis", "x-eucjp", "eucjp", "x-euc-jp"}),

+        new Charset("EUC_KR", "EUC-KR", 

+                    new String[] {"csEUCKR", "ksc5601", "5601", "ksc5601_1987", 

+                                  "ksc_5601", "ksc5601-1987", "ks_c_5601-1987", 

+                                  "euckr"}),

+        new Charset("GB18030", "GB18030", new String[] {"gb18030-2000"}),

+        new Charset("EUC_CN", "GB2312", new String[] {"x-EUC-CN", "csGB2312", "euccn", "euc-cn", "gb2312-80", "gb2312-1980", "CN-GB", "CN-GB-ISOIR165"}),

+        new Charset("GBK", "windows-936", new String[] {"CP936", "MS936", "ms_936", "x-mswin-936"}),

+

+        new Charset("Cp037", "IBM037", new String[] {"ebcdic-cp-us", "ebcdic-cp-ca", "ebcdic-cp-wt", "ebcdic-cp-nl", "csIBM037"}),

+        new Charset("Cp273", "IBM273", new String[] {"csIBM273"}),

+        new Charset("Cp277", "IBM277", new String[] {"EBCDIC-CP-DK", "EBCDIC-CP-NO", "csIBM277"}),

+        new Charset("Cp278", "IBM278", new String[] {"CP278", "ebcdic-cp-fi", "ebcdic-cp-se", "csIBM278"}),

+        new Charset("Cp280", "IBM280", new String[] {"ebcdic-cp-it", "csIBM280"}),

+        new Charset("Cp284", "IBM284", new String[] {"ebcdic-cp-es", "csIBM284"}),

+        new Charset("Cp285", "IBM285", new String[] {"ebcdic-cp-gb", "csIBM285"}),

+        new Charset("Cp297", "IBM297", new String[] {"ebcdic-cp-fr", "csIBM297"}),

+        new Charset("Cp420", "IBM420", new String[] {"ebcdic-cp-ar1", "csIBM420"}),

+        new Charset("Cp424", "IBM424", new String[] {"ebcdic-cp-he", "csIBM424"}),

+        new Charset("Cp437", "IBM437", new String[] {"437", "csPC8CodePage437"}),

+        new Charset("Cp500", "IBM500", new String[] {"ebcdic-cp-be", "ebcdic-cp-ch", "csIBM500"}),

+        new Charset("Cp775", "IBM775", new String[] {"csPC775Baltic"}),

+        new Charset("Cp838", "IBM-Thai", new String[] {}),

+        new Charset("Cp850", "IBM850", new String[] {"850", "csPC850Multilingual"}),

+        new Charset("Cp852", "IBM852", new String[] {"852", "csPCp852"}),

+        new Charset("Cp855", "IBM855", new String[] {"855", "csIBM855"}),

+        new Charset("Cp857", "IBM857", new String[] {"857", "csIBM857"}),

+        new Charset("Cp858", "IBM00858", 

+                new String[] {"CCSID00858", "CP00858", 

+                              "PC-Multilingual-850+euro"}),

+        new Charset("Cp860", "IBM860", new String[] {"860", "csIBM860"}),

+        new Charset("Cp861", "IBM861", new String[] {"861", "cp-is", "csIBM861"}),

+        new Charset("Cp862", "IBM862", new String[] {"862", "csPC862LatinHebrew"}),

+        new Charset("Cp863", "IBM863", new String[] {"863", "csIBM863"}),

+        new Charset("Cp864", "IBM864", new String[] {"cp864", "csIBM864"}),

+        new Charset("Cp865", "IBM865", new String[] {"865", "csIBM865"}),

+        new Charset("Cp866", "IBM866", new String[] {"866", "csIBM866"}),

+        new Charset("Cp868", "IBM868", new String[] {"cp-ar", "csIBM868"}),

+        new Charset("Cp869", "IBM869", new String[] {"cp-gr", "csIBM869"}),

+        new Charset("Cp870", "IBM870", new String[] {"ebcdic-cp-roece", "ebcdic-cp-yu", "csIBM870"}),

+        new Charset("Cp871", "IBM871", new String[] {"ebcdic-cp-is", "csIBM871"}),

+        new Charset("Cp918", "IBM918", new String[] {"ebcdic-cp-ar2", "csIBM918"}),

+        new Charset("Cp1026", "IBM1026", new String[] {"csIBM1026"}),

+        new Charset("Cp1047", "IBM1047", new String[] {"IBM-1047"}),

+        new Charset("Cp1140", "IBM01140", 

+                    new String[] {"CCSID01140", "CP01140", 

+                                  "ebcdic-us-37+euro"}),

+        new Charset("Cp1141", "IBM01141", 

+                    new String[] {"CCSID01141", "CP01141", 

+                                  "ebcdic-de-273+euro"}),

+        new Charset("Cp1142", "IBM01142", new String[] {"CCSID01142", "CP01142", "ebcdic-dk-277+euro", "ebcdic-no-277+euro"}),

+        new Charset("Cp1143", "IBM01143", new String[] {"CCSID01143", "CP01143", "ebcdic-fi-278+euro", "ebcdic-se-278+euro"}),

+        new Charset("Cp1144", "IBM01144", new String[] {"CCSID01144", "CP01144", "ebcdic-it-280+euro"}),

+        new Charset("Cp1145", "IBM01145", new String[] {"CCSID01145", "CP01145", "ebcdic-es-284+euro"}),

+        new Charset("Cp1146", "IBM01146", new String[] {"CCSID01146", "CP01146", "ebcdic-gb-285+euro"}),

+        new Charset("Cp1147", "IBM01147", new String[] {"CCSID01147", "CP01147", "ebcdic-fr-297+euro"}),

+        new Charset("Cp1148", "IBM01148", new String[] {"CCSID01148", "CP01148", "ebcdic-international-500+euro"}),

+        new Charset("Cp1149", "IBM01149", new String[] {"CCSID01149", "CP01149", "ebcdic-is-871+euro"}),

+        new Charset("Cp1250", "windows-1250", new String[] {}),

+        new Charset("Cp1251", "windows-1251", new String[] {}),

+        new Charset("Cp1252", "windows-1252", new String[] {}),

+        new Charset("Cp1253", "windows-1253", new String[] {}),

+        new Charset("Cp1254", "windows-1254", new String[] {}),

+        new Charset("Cp1255", "windows-1255", new String[] {}),

+        new Charset("Cp1256", "windows-1256", new String[] {}),

+        new Charset("Cp1257", "windows-1257", new String[] {}),

+        new Charset("Cp1258", "windows-1258", new String[] {}),

+        new Charset("ISO2022CN", "ISO-2022-CN", new String[] {}),

+        new Charset("ISO2022JP", "ISO-2022-JP", new String[] {"csISO2022JP", "JIS", "jis_encoding", "csjisencoding"}),

+        new Charset("ISO2022KR", "ISO-2022-KR", new String[] {"csISO2022KR"}),

+        new Charset("JIS_X0201", "JIS_X0201", new String[] {"X0201", "JIS0201", "csHalfWidthKatakana"}),

+        new Charset("JIS_X0212-1990", "JIS_X0212-1990", new String[] {"iso-ir-159", "x0212", "JIS0212", "csISO159JISX02121990"}),

+        new Charset("JIS_C6626-1983", "JIS_C6626-1983", new String[] {"x-JIS0208", "JIS0208", "csISO87JISX0208", "x0208", "JIS_X0208-1983", "iso-ir-87"}),

+        new Charset("SJIS", "Shift_JIS", new String[] {"MS_Kanji", "csShiftJIS", "shift-jis", "x-sjis", "pck"}),

+        new Charset("TIS620", "TIS-620", new String[] {}),

+        new Charset("MS932", "Windows-31J", new String[] {"windows-932", "csWindows31J", "x-ms-cp932"}),

+        new Charset("EUC_TW", "EUC-TW", new String[] {"x-EUC-TW", "cns11643", "euctw"}),

+        new Charset("x-Johab", "johab", new String[] {"johab", "cp1361", "ms1361", "ksc5601-1992", "ksc5601_1992"}),

+        new Charset("MS950_HKSCS", "", new String[] {}),

+        new Charset("MS874", "windows-874", new String[] {"cp874"}),

+        new Charset("MS949", "windows-949", new String[] {"windows949", "ms_949", "x-windows-949"}),

+        new Charset("MS950", "windows-950", new String[] {"x-windows-950"}),

+

+        new Charset("Cp737", null, new String[] {}),

+        new Charset("Cp856", null, new String[] {}),

+        new Charset("Cp875", null, new String[] {}),

+        new Charset("Cp921", null, new String[] {}),

+        new Charset("Cp922", null, new String[] {}),

+        new Charset("Cp930", null, new String[] {}),

+        new Charset("Cp933", null, new String[] {}),

+        new Charset("Cp935", null, new String[] {}),

+        new Charset("Cp937", null, new String[] {}),

+        new Charset("Cp939", null, new String[] {}),

+        new Charset("Cp942", null, new String[] {}),

+        new Charset("Cp942C", null, new String[] {}),

+        new Charset("Cp943", null, new String[] {}),

+        new Charset("Cp943C", null, new String[] {}),

+        new Charset("Cp948", null, new String[] {}),

+        new Charset("Cp949", null, new String[] {}),

+        new Charset("Cp949C", null, new String[] {}),

+        new Charset("Cp950", null, new String[] {}),

+        new Charset("Cp964", null, new String[] {}),

+        new Charset("Cp970", null, new String[] {}),

+        new Charset("Cp1006", null, new String[] {}),

+        new Charset("Cp1025", null, new String[] {}),    

+        new Charset("Cp1046", null, new String[] {}),

+        new Charset("Cp1097", null, new String[] {}),

+        new Charset("Cp1098", null, new String[] {}),

+        new Charset("Cp1112", null, new String[] {}),

+        new Charset("Cp1122", null, new String[] {}),

+        new Charset("Cp1123", null, new String[] {}),

+        new Charset("Cp1124", null, new String[] {}),

+        new Charset("Cp1381", null, new String[] {}),

+        new Charset("Cp1383", null, new String[] {}),

+        new Charset("Cp33722", null, new String[] {}),

+        new Charset("Big5_Solaris", null, new String[] {}),

+        new Charset("EUC_JP_LINUX", null, new String[] {}),

+        new Charset("EUC_JP_Solaris", null, new String[] {}),

+        new Charset("ISCII91", null, new String[] {"x-ISCII91", "iscii"}),

+        new Charset("ISO2022_CN_CNS", null, new String[] {}),

+        new Charset("ISO2022_CN_GB", null, new String[] {}),

+        new Charset("x-iso-8859-11", null, new String[] {}),

+        new Charset("JISAutoDetect", null, new String[] {}),

+        new Charset("MacArabic", null, new String[] {}),

+        new Charset("MacCentralEurope", null, new String[] {}),

+        new Charset("MacCroatian", null, new String[] {}),

+        new Charset("MacCyrillic", null, new String[] {}),

+        new Charset("MacDingbat", null, new String[] {}),

+        new Charset("MacGreek", "MacGreek", new String[] {}),

+        new Charset("MacHebrew", null, new String[] {}),

+        new Charset("MacIceland", null, new String[] {}),

+        new Charset("MacRoman", "MacRoman", new String[] {"Macintosh", "MAC", "csMacintosh"}),

+        new Charset("MacRomania", null, new String[] {}),

+        new Charset("MacSymbol", null, new String[] {}),

+        new Charset("MacThai", null, new String[] {}),

+        new Charset("MacTurkish", null, new String[] {}),

+        new Charset("MacUkraine", null, new String[] {}),

+        new Charset("UnicodeBig", null, new String[] {}),

+        new Charset("UnicodeLittle", null, new String[] {})

+    };

+

+    /**

+     * Contains the canonical names of character sets which can be used to 

+     * decode bytes into Java chars.

+     */

+    private static SortedSet<String> decodingSupported = null;

+    

+    /**

+     * Contains the canonical names of character sets which can be used to 

+     * encode Java chars into bytes.

+     */

+    private static SortedSet<String> encodingSupported = null;

+    

+    /**

+     * Maps character set names to Charset objects. All possible names of

+     * a charset will be mapped to the Charset.

+     */

+    private static Map<String, Charset> charsetMap = null;

+    

+    static {

+        decodingSupported = new TreeSet<String>();

+        encodingSupported = new TreeSet<String>();

+        byte[] dummy = new byte[] {'d', 'u', 'm', 'm', 'y'};

+        for (Charset c : JAVA_CHARSETS) {

+            try {

+                new String(dummy, c.canonical);

+                decodingSupported.add(c.canonical.toLowerCase());

+            } catch (UnsupportedOperationException e) {

+            } catch (UnsupportedEncodingException e) {

+            }

+            try {

+                "dummy".getBytes(c.canonical);

+                encodingSupported.add(c.canonical.toLowerCase());

+            } catch (UnsupportedOperationException e) {

+            } catch (UnsupportedEncodingException e) {

+            }

+        }

+        

+        charsetMap = new HashMap<String, Charset>();

+        for (Charset c : JAVA_CHARSETS) {

+            charsetMap.put(c.canonical.toLowerCase(), c);

+            if (c.mime != null) {

+                charsetMap.put(c.mime.toLowerCase(), c);

+            }

+            if (c.aliases != null) {

+                for (String str : c.aliases) {

+                    charsetMap.put(str.toLowerCase(), c);

+                }

+            }

+        }

+        

+        if (log.isDebugEnabled()) {

+            log.debug("Character sets which support decoding: " 

+                        + decodingSupported);

+            log.debug("Character sets which support encoding: " 

+                        + encodingSupported);

+        }

+    }

+

+    /** carriage return - line feed sequence */

+    public static final String CRLF = "\r\n";

+

+    /** US-ASCII CR, carriage return (13) */

+    public static final int CR = '\r';

+

+    /** US-ASCII LF, line feed (10) */

+    public static final int LF = '\n';

+

+    /** US-ASCII SP, space (32) */

+    public static final int SP = ' ';

+

+    /** US-ASCII HT, horizontal-tab (9) */

+    public static final int HT = '\t';

+

+    public static final java.nio.charset.Charset US_ASCII = java.nio.charset.Charset

+            .forName("US-ASCII");

+

+    public static final java.nio.charset.Charset ISO_8859_1 = java.nio.charset.Charset

+            .forName("ISO-8859-1");

+

+    public static final java.nio.charset.Charset UTF_8 = java.nio.charset.Charset

+            .forName("UTF-8");

+

+    public static final java.nio.charset.Charset DEFAULT_CHARSET = US_ASCII;

+

+    /**

+     * Returns <code>true</code> if the specified character falls into the US

+     * ASCII character set (Unicode range 0000 to 007f).

+     * 

+     * @param ch

+     *            character to test.

+     * @return <code>true</code> if the specified character falls into the US

+     *         ASCII character set, <code>false</code> otherwise.

+     */

+    public static boolean isASCII(char ch) {

+        return (0xFF80 & ch) == 0;

+    }

+

+    /**

+     * Returns <code>true</code> if the specified string consists entirely of

+     * US ASCII characters.

+     * 

+     * @param s

+     *            string to test.

+     * @return <code>true</code> if the specified string consists entirely of

+     *         US ASCII characters, <code>false</code> otherwise.

+     */

+    public static boolean isASCII(final String s) {

+        if (s == null) {

+            throw new IllegalArgumentException("String may not be null");

+        }

+        final int len = s.length();

+        for (int i = 0; i < len; i++) {

+            if (!isASCII(s.charAt(i))) {

+                return false;

+            }

+        }

+        return true;

+    }

+

+    /**

+     * Returns <code>true</code> if the specified character is a whitespace

+     * character (CR, LF, SP or HT).

+     * 

+     * @param ch

+     *            character to test.

+     * @return <code>true</code> if the specified character is a whitespace

+     *         character, <code>false</code> otherwise.

+     */

+    public static boolean isWhitespace(char ch) {

+        return ch == SP || ch == HT || ch == CR || ch == LF;

+    }

+

+    /**

+     * Returns <code>true</code> if the specified string consists entirely of

+     * whitespace characters.

+     * 

+     * @param s

+     *            string to test.

+     * @return <code>true</code> if the specified string consists entirely of

+     *         whitespace characters, <code>false</code> otherwise.

+     */

+    public static boolean isWhitespace(final String s) {

+        if (s == null) {

+            throw new IllegalArgumentException("String may not be null");

+        }

+        final int len = s.length();

+        for (int i = 0; i < len; i++) {

+            if (!isWhitespace(s.charAt(i))) {

+                return false;

+            }

+        }

+        return true;

+    }

+    

+    /**

+     * Determines if the VM supports encoding (chars to bytes) the 

+     * specified character set. NOTE: the given character set name may 

+     * not be known to the VM even if this method returns <code>true</code>.

+     * Use {@link #toJavaCharset(String)} to get the canonical Java character

+     * set name.

+     * 

+     * @param charsetName the characters set name.

+     * @return <code>true</code> if encoding is supported, <code>false</code>

+     *         otherwise.

+     */

+    public static boolean isEncodingSupported(String charsetName) {

+        return encodingSupported.contains(charsetName.toLowerCase());

+    }

+    

+    /**

+     * Determines if the VM supports decoding (bytes to chars) the 

+     * specified character set. NOTE: the given character set name may 

+     * not be known to the VM even if this method returns <code>true</code>.

+     * Use {@link #toJavaCharset(String)} to get the canonical Java character

+     * set name.

+     * 

+     * @param charsetName the characters set name.

+     * @return <code>true</code> if decoding is supported, <code>false</code>

+     *         otherwise.

+     */

+    public static boolean isDecodingSupported(String charsetName) {

+        return decodingSupported.contains(charsetName.toLowerCase());

+    }

+    

+    /**

+     * Gets the preferred MIME character set name for the specified

+     * character set or <code>null</code> if not known.

+     * 

+     * @param charsetName the character set name to look for.

+     * @return the MIME preferred name or <code>null</code> if not known.

+     */

+    public static String toMimeCharset(String charsetName) {

+        Charset c = charsetMap.get(charsetName.toLowerCase());

+        if (c != null) {

+            return c.mime;

+        }

+        return null;

+    }

+    

+    /**

+     * Gets the canonical Java character set name for the specified

+     * character set or <code>null</code> if not known. This should be

+     * called before doing any conversions using the Java API. NOTE:

+     * you must use {@link #isEncodingSupported(String)} or

+     * {@link #isDecodingSupported(String)} to make sure the returned

+     * Java character set is supported by the current VM.

+     * 

+     * @param charsetName the character set name to look for.

+     * @return the canonical Java name or <code>null</code> if not known.

+     */

+    public static String toJavaCharset(String charsetName) {

+        Charset c = charsetMap.get(charsetName.toLowerCase());

+        if (c != null) {

+            return c.canonical;

+        }

+        return null;

+    }

+

+    public static java.nio.charset.Charset getCharset(String charsetName) {

+        String defaultCharset = "ISO-8859-1";

+        

+        // Use the default chareset if given charset is null

+        if(charsetName == null) charsetName = defaultCharset;

+            

+        try {

+            return java.nio.charset.Charset.forName(charsetName);

+        } catch (IllegalCharsetNameException e) {

+            log.info("Illegal charset " + charsetName + ", fallback to " + defaultCharset + ": " + e);

+            // Use default charset on exception 

+            return java.nio.charset.Charset.forName(defaultCharset);

+        } catch (UnsupportedCharsetException ex) {

+            log.info("Unsupported charset " + charsetName + ", fallback to " + defaultCharset + ": " + ex);

+            // Use default charset on exception

+            return java.nio.charset.Charset.forName(defaultCharset);

+        }

+        

+    }

+    /*

+     * Uncomment the code below and run the main method to regenerate the

+     * Javadoc table above when the known charsets change. 

+     */

+    

+    /*

+    private static String dumpHtmlTable() {

+        List<Charset> l = new LinkedList<Charset>(Arrays.asList(JAVA_CHARSETS));

+        Collections.sort(l);

+        StringBuilder sb = new StringBuilder();

+        sb.append(" * <table>\n");

+        sb.append(" *     <tr>\n");

+        sb.append(" *         <td>Canonical (Java) name</td>\n");

+        sb.append(" *         <td>MIME preferred</td>\n");

+        sb.append(" *         <td>Aliases</td>\n");

+        sb.append(" *     </tr>\n");

+

+        for (Charset c : l) {

+            sb.append(" *     <tr>\n");

+            sb.append(" *         <td>" + c.canonical + "</td>\n");

+            sb.append(" *         <td>" + (c.mime == null ? "?" : c.mime)+ "</td>\n");

+            sb.append(" *         <td>");

+            for (int i = 0; c.aliases != null && i < c.aliases.length; i++) {

+                sb.append(c.aliases[i] + " ");

+            }

+            sb.append("</td>\n");

+            sb.append(" *     </tr>\n");

+        }

+        sb.append(" * </table>\n");

+        return sb.toString();

+    }

+    

+    public static void main(String[] args) {

+        System.out.println(dumpHtmlTable());

+    }

+    */

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ContentUtil.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ContentUtil.java
new file mode 100644
index 0000000..659e261
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/ContentUtil.java
@@ -0,0 +1,138 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * Utility methods for converting textual content of a message.
+ */
+public class ContentUtil {
+
+    private ContentUtil() {
+    }
+
+    /**
+     * Encodes the specified string into an immutable sequence of bytes using
+     * the US-ASCII charset.
+     * 
+     * @param string
+     *            string to encode.
+     * @return encoded string as an immutable sequence of bytes.
+     */
+    public static ByteSequence encode(String string) {
+        return encode(CharsetUtil.US_ASCII, string);
+    }
+
+    /**
+     * Encodes the specified string into an immutable sequence of bytes using
+     * the specified charset.
+     * 
+     * @param charset
+     *            Java charset to be used for the conversion.
+     * @param string
+     *            string to encode.
+     * @return encoded string as an immutable sequence of bytes.
+     */
+    public static ByteSequence encode(Charset charset, String string) {
+        ByteBuffer encoded = charset.encode(CharBuffer.wrap(string));
+        ByteArrayBuffer bab = new ByteArrayBuffer(encoded.remaining());
+        bab.append(encoded.array(), encoded.position(), encoded.remaining());
+        return bab;
+    }
+
+    /**
+     * Decodes the specified sequence of bytes into a string using the US-ASCII
+     * charset.
+     * 
+     * @param byteSequence
+     *            sequence of bytes to decode.
+     * @return decoded string.
+     */
+    public static String decode(ByteSequence byteSequence) {
+        return decode(CharsetUtil.US_ASCII, byteSequence, 0, byteSequence
+                .length());
+    }
+
+    /**
+     * Decodes the specified sequence of bytes into a string using the specified
+     * charset.
+     * 
+     * @param charset
+     *            Java charset to be used for the conversion.
+     * @param byteSequence
+     *            sequence of bytes to decode.
+     * @return decoded string.
+     */
+    public static String decode(Charset charset, ByteSequence byteSequence) {
+        return decode(charset, byteSequence, 0, byteSequence.length());
+    }
+
+    /**
+     * Decodes a sub-sequence of the specified sequence of bytes into a string
+     * using the US-ASCII charset.
+     * 
+     * @param byteSequence
+     *            sequence of bytes to decode.
+     * @param offset
+     *            offset into the byte sequence.
+     * @param length
+     *            number of bytes.
+     * @return decoded string.
+     */
+    public static String decode(ByteSequence byteSequence, int offset,
+            int length) {
+        return decode(CharsetUtil.US_ASCII, byteSequence, offset, length);
+    }
+
+    /**
+     * Decodes a sub-sequence of the specified sequence of bytes into a string
+     * using the specified charset.
+     * 
+     * @param charset
+     *            Java charset to be used for the conversion.
+     * @param byteSequence
+     *            sequence of bytes to decode.
+     * @param offset
+     *            offset into the byte sequence.
+     * @param length
+     *            number of bytes.
+     * @return decoded string.
+     */
+    public static String decode(Charset charset, ByteSequence byteSequence,
+            int offset, int length) {
+        if (byteSequence instanceof ByteArrayBuffer) {
+            ByteArrayBuffer bab = (ByteArrayBuffer) byteSequence;
+            return decode(charset, bab.buffer(), offset, length);
+        } else {
+            byte[] bytes = byteSequence.toByteArray();
+            return decode(charset, bytes, offset, length);
+        }
+    }
+
+    private static String decode(Charset charset, byte[] buffer, int offset,
+            int length) {
+        return charset.decode(ByteBuffer.wrap(buffer, offset, length))
+                .toString();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/EmptyByteSequence.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/EmptyByteSequence.java
new file mode 100644
index 0000000..01cdd19
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/EmptyByteSequence.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+final class EmptyByteSequence implements ByteSequence {
+    private static final byte[] EMPTY_BYTES = {};
+
+    public int length() {
+        return 0;
+    }
+
+    public byte byteAt(int index) {
+        throw new IndexOutOfBoundsException();
+    }
+
+    public byte[] toByteArray() {
+        return EMPTY_BYTES;
+    }
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/MimeUtil.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/MimeUtil.java
new file mode 100644
index 0000000..d87b905
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/MimeUtil.java
@@ -0,0 +1,545 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.util;

+

+import java.text.DateFormat;

+import java.text.FieldPosition;

+import java.text.SimpleDateFormat;

+import java.util.Date;

+import java.util.GregorianCalendar;

+import java.util.HashMap;

+import java.util.Locale;

+import java.util.Map;

+import java.util.Random;

+import java.util.TimeZone;

+

+import org.apache.commons.logging.Log;

+import org.apache.commons.logging.LogFactory;

+

+/**

+ * A utility class, which provides some MIME related application logic.

+ */

+public final class MimeUtil {

+    private static final Log log = LogFactory.getLog(MimeUtil.class);

+    

+    /**

+     * The <code>quoted-printable</code> encoding.

+     */

+    public static final String ENC_QUOTED_PRINTABLE = "quoted-printable";

+    /**

+     * The <code>binary</code> encoding.

+     */

+    public static final String ENC_BINARY = "binary";

+    /**

+     * The <code>base64</code> encoding.

+     */

+    public static final String ENC_BASE64 = "base64";

+    /**

+     * The <code>8bit</code> encoding.

+     */

+    public static final String ENC_8BIT = "8bit";

+    /**

+     * The <code>7bit</code> encoding.

+     */

+    public static final String ENC_7BIT = "7bit";

+

+    /** <code>MIME-Version</code> header name (lowercase) */

+    public static final String MIME_HEADER_MIME_VERSION = "mime-version";

+    /** <code>Content-ID</code> header name (lowercase) */

+    public static final String MIME_HEADER_CONTENT_ID = "content-id";

+    /** <code>Content-Description</code> header name (lowercase) */

+    public static final String MIME_HEADER_CONTENT_DESCRIPTION = "content-description";

+    /** 

+     * <code>Content-Disposition</code> header name (lowercase). 

+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 

+     */

+    public static final String MIME_HEADER_CONTENT_DISPOSITION = "content-disposition";

+    /** 

+     * <code>Content-Disposition</code> filename parameter (lowercase). 

+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 

+     */

+    public static final String PARAM_FILENAME = "filename";

+    /** 

+     * <code>Content-Disposition</code> modification-date parameter (lowercase). 

+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 

+     */

+    public static final String PARAM_MODIFICATION_DATE = "modification-date";

+    /** 

+     * <code>Content-Disposition</code> creation-date parameter (lowercase). 

+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 

+     */

+    public static final String PARAM_CREATION_DATE = "creation-date";

+    /** 

+     * <code>Content-Disposition</code> read-date parameter (lowercase). 

+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 

+     */

+    public static final String PARAM_READ_DATE = "read-date";

+    /** 

+     * <code>Content-Disposition</code> size parameter (lowercase). 

+     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 

+     */

+    public static final String PARAM_SIZE = "size";

+    /**

+     * <code>Content-Langauge</code> header (lower case).

+     * See <a href='http://www.faqs.org/rfcs/rfc4646.html'>RFC4646</a>.

+     */

+    public static final String MIME_HEADER_LANGAUGE = "content-language";

+    /**

+     * <code>Content-Location</code> header (lower case).

+     * See <a href='http://www.faqs.org/rfcs/rfc2557.html'>RFC2557</a>.

+     */

+    public static final String MIME_HEADER_LOCATION = "content-location";

+    /**

+     * <code>Content-MD5</code> header (lower case).

+     * See <a href='http://www.faqs.org/rfcs/rfc1864.html'>RFC1864</a>.

+     */

+    public static final String MIME_HEADER_MD5 = "content-md5";

+

+    // used to create unique ids

+    private static final Random random = new Random();

+    

+    // used to create unique ids

+    private static int counter = 0;

+

+    private MimeUtil() {

+        // this is an utility class to be used statically.

+        // this constructor protect from instantiation.

+    }

+    

+    /**

+     * Returns, whether the given two MIME types are identical.

+     */

+    public static boolean isSameMimeType(String pType1, String pType2) {

+        return pType1 != null  &&  pType2 != null  &&  pType1.equalsIgnoreCase(pType2);

+    }

+

+    /**

+     * Returns true, if the given MIME type is that of a message. 

+     */

+    public static boolean isMessage(String pMimeType) {

+        return pMimeType != null  &&  pMimeType.equalsIgnoreCase("message/rfc822");

+    }

+

+    /**

+     * Return true, if the given MIME type indicates a multipart entity.

+     */

+    public static boolean isMultipart(String pMimeType) {

+        return pMimeType != null  &&  pMimeType.toLowerCase().startsWith("multipart/");

+    }

+

+    /**

+     * Returns, whether the given transfer-encoding is "base64".

+     */

+    public static boolean isBase64Encoding(String pTransferEncoding) {

+        return ENC_BASE64.equalsIgnoreCase(pTransferEncoding);

+    }

+

+    /**

+     * Returns, whether the given transfer-encoding is "quoted-printable".

+     */

+    public static boolean isQuotedPrintableEncoded(String pTransferEncoding) {

+        return ENC_QUOTED_PRINTABLE.equalsIgnoreCase(pTransferEncoding);

+    }

+

+    /**

+     * <p>Parses a complex field value into a map of key/value pairs. You may

+     * use this, for example, to parse a definition like

+     * <pre>

+     *   text/plain; charset=UTF-8; boundary=foobar

+     * </pre>

+     * The above example would return a map with the keys "", "charset",

+     * and "boundary", and the values "text/plain", "UTF-8", and "foobar".

+     * </p><p>

+     * Header value will be unfolded and excess white space trimmed.

+     * </p>

+     * @param pValue The field value to parse.

+     * @return The result map; use the key "" to retrieve the first value.

+     */

+    @SuppressWarnings("fallthrough")

+    public static Map<String, String> getHeaderParams(String pValue) {

+        pValue = pValue.trim();

+

+        pValue = unfold(pValue);

+        

+        Map<String, String> result = new HashMap<String, String>();

+

+        // split main value and parameters

+        String main;

+        String rest;

+        if (pValue.indexOf(";") == -1) {

+            main = pValue;

+            rest = null;

+        } else {

+            main = pValue.substring(0, pValue.indexOf(";"));

+            rest = pValue.substring(main.length() + 1);

+        }

+

+        result.put("", main);

+        if (rest != null) {

+            char[] chars = rest.toCharArray();

+            StringBuilder paramName = new StringBuilder(64);

+            StringBuilder paramValue = new StringBuilder(64);

+

+            final byte READY_FOR_NAME = 0;

+            final byte IN_NAME = 1;

+            final byte READY_FOR_VALUE = 2;

+            final byte IN_VALUE = 3;

+            final byte IN_QUOTED_VALUE = 4;

+            final byte VALUE_DONE = 5;

+            final byte ERROR = 99;

+

+            byte state = READY_FOR_NAME;

+            boolean escaped = false;

+            for (char c : chars) {

+                switch (state) {

+                    case ERROR:

+                        if (c == ';')

+                            state = READY_FOR_NAME;

+                        break;

+

+                    case READY_FOR_NAME:

+                        if (c == '=') {

+                            log.error("Expected header param name, got '='");

+                            state = ERROR;

+                            break;

+                        }

+

+                        paramName.setLength(0);

+                        paramValue.setLength(0);

+

+                        state = IN_NAME;

+                        // fall-through

+

+                    case IN_NAME:

+                        if (c == '=') {

+                            if (paramName.length() == 0)

+                                state = ERROR;

+                            else

+                                state = READY_FOR_VALUE;

+                            break;

+                        }

+

+                        // not '='... just add to name

+                        paramName.append(c);

+                        break;

+

+                    case READY_FOR_VALUE:

+                        boolean fallThrough = false;

+                        switch (c) {

+                            case ' ':

+                            case '\t':

+                                break;  // ignore spaces, especially before '"'

+

+                            case '"':

+                                state = IN_QUOTED_VALUE;

+                                break;

+

+                            default:

+                                state = IN_VALUE;

+                                fallThrough = true;

+                                break;

+                        }

+                        if (!fallThrough)

+                            break;

+

+                        // fall-through

+

+                    case IN_VALUE:

+                        fallThrough = false;

+                        switch (c) {

+                            case ';':

+                            case ' ':

+                            case '\t':

+                                result.put(

+                                   paramName.toString().trim().toLowerCase(),

+                                   paramValue.toString().trim());

+                                state = VALUE_DONE;

+                                fallThrough = true;

+                                break;

+                            default:

+                                paramValue.append(c);

+                                break;

+                        }

+                        if (!fallThrough)

+                            break;

+

+                    case VALUE_DONE:

+                        switch (c) {

+                            case ';':

+                                state = READY_FOR_NAME;

+                                break;

+

+                            case ' ':

+                            case '\t':

+                                break;

+

+                            default:

+                                state = ERROR;

+                                break;

+                        }

+                        break;

+                        

+                    case IN_QUOTED_VALUE:

+                        switch (c) {

+                            case '"':

+                                if (!escaped) {

+                                    // don't trim quoted strings; the spaces could be intentional.

+                                    result.put(

+                                            paramName.toString().trim().toLowerCase(),

+                                            paramValue.toString());

+                                    state = VALUE_DONE;

+                                } else {

+                                    escaped = false;

+                                    paramValue.append(c);                                    

+                                }

+                                break;

+                                

+                            case '\\':

+                                if (escaped) {

+                                    paramValue.append('\\');

+                                }

+                                escaped = !escaped;

+                                break;

+

+                            default:

+                                if (escaped) {

+                                    paramValue.append('\\');

+                                }

+                                escaped = false;

+                                paramValue.append(c);

+                                break;

+                        }

+                        break;

+

+                }

+            }

+

+            // done looping.  check if anything is left over.

+            if (state == IN_VALUE) {

+                result.put(

+                        paramName.toString().trim().toLowerCase(),

+                        paramValue.toString().trim());

+            }

+        }

+

+        return result;

+    }

+

+    /**

+     * Creates a new unique message boundary string that can be used as boundary

+     * parameter for the Content-Type header field of a message.

+     * 

+     * @return a new unique message boundary string.

+     */

+    public static String createUniqueBoundary() {

+        StringBuilder sb = new StringBuilder();

+        sb.append("-=Part.");

+        sb.append(Integer.toHexString(nextCounterValue()));

+        sb.append('.');

+        sb.append(Long.toHexString(random.nextLong()));

+        sb.append('.');

+        sb.append(Long.toHexString(System.currentTimeMillis()));

+        sb.append('.');

+        sb.append(Long.toHexString(random.nextLong()));

+        sb.append("=-");

+        return sb.toString();

+    }

+

+    /**

+     * Creates a new unique message identifier that can be used in message

+     * header field such as Message-ID or In-Reply-To. If the given host name is

+     * not <code>null</code> it will be used as suffix for the message ID

+     * (following an at sign).

+     * 

+     * The resulting string is enclosed in angle brackets (&lt; and &gt;);

+     * 

+     * @param hostName host name to be included in the message ID or

+     *            <code>null</code> if no host name should be included.

+     * @return a new unique message identifier.

+     */

+    public static String createUniqueMessageId(String hostName) {

+        StringBuilder sb = new StringBuilder("<Mime4j.");

+        sb.append(Integer.toHexString(nextCounterValue()));

+        sb.append('.');

+        sb.append(Long.toHexString(random.nextLong()));

+        sb.append('.');

+        sb.append(Long.toHexString(System.currentTimeMillis()));

+        if (hostName != null) {

+            sb.append('@');

+            sb.append(hostName);

+        }

+        sb.append('>');

+        return sb.toString();

+    }

+

+    /**

+     * Formats the specified date into a RFC 822 date-time string.

+     * 

+     * @param date

+     *            date to be formatted into a string.

+     * @param zone

+     *            the time zone to use or <code>null</code> to use the default

+     *            time zone.

+     * @return the formatted time string.

+     */

+    public static String formatDate(Date date, TimeZone zone) {

+        DateFormat df = RFC822_DATE_FORMAT.get();

+

+        if (zone == null) {

+            df.setTimeZone(TimeZone.getDefault());

+        } else {

+            df.setTimeZone(zone);

+        }

+

+        return df.format(date);

+    }

+

+    /**

+     * Splits the specified string into a multiple-line representation with

+     * lines no longer than 76 characters (because the line might contain

+     * encoded words; see <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC

+     * 2047</a> section 2). If the string contains non-whitespace sequences

+     * longer than 76 characters a line break is inserted at the whitespace

+     * character following the sequence resulting in a line longer than 76

+     * characters.

+     * 

+     * @param s

+     *            string to split.

+     * @param usedCharacters

+     *            number of characters already used up. Usually the number of

+     *            characters for header field name plus colon and one space.

+     * @return a multiple-line representation of the given string.

+     */

+    public static String fold(String s, int usedCharacters) {

+        final int maxCharacters = 76;

+

+        final int length = s.length();

+        if (usedCharacters + length <= maxCharacters)

+            return s;

+

+        StringBuilder sb = new StringBuilder();

+

+        int lastLineBreak = -usedCharacters;

+        int wspIdx = indexOfWsp(s, 0);

+        while (true) {

+            if (wspIdx == length) {

+                sb.append(s.substring(Math.max(0, lastLineBreak)));

+                return sb.toString();

+            }

+

+            int nextWspIdx = indexOfWsp(s, wspIdx + 1);

+

+            if (nextWspIdx - lastLineBreak > maxCharacters) {

+                sb.append(s.substring(Math.max(0, lastLineBreak), wspIdx));

+                sb.append("\r\n");

+                lastLineBreak = wspIdx;

+            }

+

+            wspIdx = nextWspIdx;

+        }

+    }

+

+    /**

+     * Unfold a multiple-line representation into a single line.

+     * 

+     * @param s

+     *            string to unfold.

+     * @return unfolded string.

+     */

+    public static String unfold(String s) {

+        final int length = s.length();

+        for (int idx = 0; idx < length; idx++) {

+            char c = s.charAt(idx);

+            if (c == '\r' || c == '\n') {

+                return unfold0(s, idx);

+            }

+        }

+

+        return s;

+    }

+

+    private static String unfold0(String s, int crlfIdx) {

+        final int length = s.length();

+        StringBuilder sb = new StringBuilder(length);

+

+        if (crlfIdx > 0) {

+            sb.append(s.substring(0, crlfIdx));

+        }

+

+        for (int idx = crlfIdx + 1; idx < length; idx++) {

+            char c = s.charAt(idx);

+            if (c != '\r' && c != '\n') {

+                sb.append(c);

+            }

+        }

+

+        return sb.toString();

+    }

+

+    private static int indexOfWsp(String s, int fromIndex) {

+        final int len = s.length();

+        for (int index = fromIndex; index < len; index++) {

+            char c = s.charAt(index);

+            if (c == ' ' || c == '\t')

+                return index;

+        }

+        return len;

+    }

+

+    private static synchronized int nextCounterValue() {

+        return counter++;

+    }

+

+    private static final ThreadLocal<DateFormat> RFC822_DATE_FORMAT = new ThreadLocal<DateFormat>() {

+        @Override

+        protected DateFormat initialValue() {

+            return new Rfc822DateFormat();

+        }

+    };

+

+    private static final class Rfc822DateFormat extends SimpleDateFormat {

+        private static final long serialVersionUID = 1L;

+

+        public Rfc822DateFormat() {

+            super("EEE, d MMM yyyy HH:mm:ss ", Locale.US);

+        }

+

+        @Override

+        public StringBuffer format(Date date, StringBuffer toAppendTo,

+                FieldPosition pos) {

+            StringBuffer sb = super.format(date, toAppendTo, pos);

+

+            int zoneMillis = calendar.get(GregorianCalendar.ZONE_OFFSET);

+            int dstMillis = calendar.get(GregorianCalendar.DST_OFFSET);

+            int minutes = (zoneMillis + dstMillis) / 1000 / 60;

+

+            if (minutes < 0) {

+                sb.append('-');

+                minutes = -minutes;

+            } else {

+                sb.append('+');

+            }

+

+            sb.append(String.format("%02d%02d", minutes / 60, minutes % 60));

+

+            return sb;

+        }

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/StringArrayMap.java b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/StringArrayMap.java
new file mode 100644
index 0000000..d7639ce
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/java/org/apache/james/mime4j/util/StringArrayMap.java
@@ -0,0 +1,253 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.util;

+

+import java.io.Serializable;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.Collections;

+import java.util.Enumeration;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+import java.util.NoSuchElementException;

+

+import org.apache.james.mime4j.message.Header;

+import org.apache.james.mime4j.parser.ContentHandler;

+import org.apache.james.mime4j.parser.Field;

+

+/**

+ * An object, which may be used to implement header, or parameter

+ * maps. The maps keys are the header or parameter names. The

+ * maps values are strings (single value), lists, or arrays.

+ * <p>

+ * Note that this class is not directly used anywhere in Mime4j.

+ * Instead a user might choose to use it instead of {@link Header}

+ * and {@link Field} in a custom {@link ContentHandler} implementation.

+ * See also MIME4j-24.

+ */

+public class StringArrayMap implements Serializable {

+    private static final long serialVersionUID = -5833051164281786907L;

+    private final Map<String, Object> map = new HashMap<String, Object>();

+

+    /**

+     * <p>Converts the given object into a string. The object may be either of:

+     * <ul>

+     *   <li>a string, which is returned without conversion</li>

+     *   <li>a list of strings, in which case the first element is returned</li>

+     *   <li>an array of strings, in which case the first element is returned</li>

+     * </ul>

+     */

+    public static String asString(Object pValue) {

+        if (pValue == null) {

+            return null;

+        }

+        if (pValue instanceof String) {

+            return (String) pValue;

+        }

+        if (pValue instanceof String[]) {

+            return ((String[]) pValue)[0];

+        }

+        if (pValue instanceof List) {

+            return (String) ((List<?>) pValue).get(0);

+        }

+        throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName());

+    }

+

+    /**

+     * <p>Converts the given object into a string array. The object may be either of:

+     * <ul>

+     *   <li>a string, which is returned as an array with one element</li>

+     *   <li>a list of strings, which is being converted into a string array</li>

+     *   <li>an array of strings, which is returned without conversion</li>

+     * </ul>

+     */

+    public static String[] asStringArray(Object pValue) {

+        if (pValue == null) {

+            return null;

+        }

+        if (pValue instanceof String) {

+            return new String[]{(String) pValue};

+        }

+        if (pValue instanceof String[]) {

+            return (String[]) pValue;

+        }

+        if (pValue instanceof List) {

+            final List<?> l = (List<?>) pValue;

+            return l.toArray(new String[l.size()]);

+        }

+        throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName());

+    }

+

+    /**

+     * <p>Converts the given object into a string enumeration. The object may be either of:

+     * <ul>

+     *   <li>a string, which is returned as an enumeration with one element</li>

+     *   <li>a list of strings, which is being converted into a string enumeration</li>

+     *   <li>an array of strings, which is being converted into a string enumeration</li>

+     * </ul>

+     */

+    public static Enumeration<String> asStringEnum(final Object pValue) {

+        if (pValue == null) {

+            return null;

+        }

+        if (pValue instanceof String) {

+            return new Enumeration<String>(){

+                private Object value = pValue;

+                public boolean hasMoreElements() {

+                    return value != null;

+                }

+                public String nextElement() {

+                    if (value == null) {

+                        throw new NoSuchElementException();

+                    }

+                    final String s = (String) value;

+                    value = null;

+                    return s;

+                }

+            };

+        }

+        if (pValue instanceof String[]) {

+            final String[] values = (String[]) pValue;

+            return new Enumeration<String>() {

+                private int offset;

+                public boolean hasMoreElements() {

+                    return offset < values.length;

+                }

+                public String nextElement() {

+                    if (offset >= values.length) {

+                        throw new NoSuchElementException();

+                    }

+                    return values[offset++];

+                }

+            };

+        }

+        if (pValue instanceof List) {

+            @SuppressWarnings("unchecked")

+            final List<String> stringList = (List<String>) pValue; 

+            return Collections.enumeration(stringList);

+        }

+        throw new IllegalStateException("Invalid parameter class: " + pValue.getClass().getName());

+    }

+

+    /**

+     * Converts the given map into a string array map: The map values

+     * are string arrays.

+     */

+    public static Map<String, String[]> asMap(final Map<String, Object> pMap) {

+        Map<String, String[]> result = new HashMap<String, String[]>(pMap.size());

+        for (Map.Entry<String, Object> entry : pMap.entrySet()) {

+            final String[] value = asStringArray(entry.getValue());

+            result.put(entry.getKey(), value);

+        }

+        return Collections.unmodifiableMap(result);

+    }

+

+    /**

+     * Adds a value to the given map.

+     */

+    protected void addMapValue(Map<String, Object> pMap, String pName, String pValue) {

+        Object o = pMap.get(pName);

+        if (o == null) {

+            o = pValue;

+        } else if (o instanceof String) {

+            final List<Object> list = new ArrayList<Object>();

+            list.add(o);

+            list.add(pValue);

+            o = list;

+        } else if (o instanceof List) {

+            @SuppressWarnings("unchecked")

+            final List<String> stringList = (List<String>) o; 

+            stringList.add(pValue);

+        } else if (o instanceof String[]) {

+            final List<String> list = new ArrayList<String>();

+            final String[] arr = (String[]) o;

+            for (String str : arr) {

+                list.add(str);

+            }

+            list.add(pValue);

+            o = list;

+        } else {

+            throw new IllegalStateException("Invalid object type: " + o.getClass().getName());

+        }

+        pMap.put(pName, o);

+    }

+

+    /**

+     * Lower cases the given name.

+     */

+    protected String convertName(String pName) {

+        return pName.toLowerCase();

+    }

+

+    /**

+     * Returns the requested value.

+     */

+    public String getValue(String pName) {

+        return asString(map.get(convertName(pName)));

+    }

+

+    /**

+     * Returns the requested values as a string array.

+     */

+    public String[] getValues(String pName) {

+        return asStringArray(map.get(convertName(pName)));

+    }

+

+    /**

+     * Returns the requested values as an enumeration.

+     */

+    public Enumeration<String> getValueEnum(String pName) {

+        return asStringEnum(map.get(convertName(pName)));

+    }

+

+    /**

+     * Returns the set of registered names as an enumeration.

+     * @see #getNameArray()

+     */

+    public Enumeration<String> getNames() {

+        return Collections.enumeration(map.keySet());

+    }

+

+    /**

+     * Returns an unmodifiable map of name/value pairs. The map keys

+     * are the lower cased parameter/header names. The map values are

+     * string arrays.

+     */

+    public Map<String, String[]> getMap() {

+        return asMap(map);

+    }

+

+    /**

+     * Adds a new name/value pair.

+     */

+    public void addValue(String pName, String pValue) {

+        addMapValue(map, convertName(pName), pValue);

+    }

+

+    /**

+     * Returns the set of registered names.

+     * @see #getNames()

+     */

+    public String[] getNameArray() {

+        final Collection<String> c = map.keySet();

+        return c.toArray(new String[c.size()]);

+    }

+}

diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contentdisposition/ContentDispositionParser.jj b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contentdisposition/ContentDispositionParser.jj
new file mode 100644
index 0000000..71eb6e5
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contentdisposition/ContentDispositionParser.jj
@@ -0,0 +1,231 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+
+/**
+ * RFC2183 Content-Disposition parser.
+ */
+
+options {
+	STATIC=false;
+	LOOKAHEAD=1;
+	JDK_VERSION = "1.5";
+	OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";
+	//DEBUG_PARSER=true;
+	//DEBUG_TOKEN_MANAGER=true;
+}
+
+PARSER_BEGIN(ContentDispositionParser)
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.mime4j.field.contentdisposition.parser;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class ContentDispositionParser {
+
+    private String dispositionType;
+    private List<String> paramNames = new ArrayList<String>();
+    private List<String> paramValues = new ArrayList<String>();
+
+    public String getDispositionType() {
+        return dispositionType;
+    }
+
+    public List<String> getParamNames() {
+        return paramNames;
+    }
+
+    public List<String> getParamValues() {
+        return paramValues;
+    }
+
+    public static void main(String args[]) throws ParseException {
+        while (true) {
+            try {
+                ContentDispositionParser parser = new ContentDispositionParser(
+                        System.in);
+                parser.parseLine();
+            } catch (Exception x) {
+                x.printStackTrace();
+                return;
+            }
+        }
+    }
+}
+
+PARSER_END(ContentDispositionParser)
+
+void parseLine() :
+{}
+{
+	parse() ["\r"] "\n"
+}
+
+void parseAll() :
+{}
+{
+	parse() <EOF>
+}
+
+void parse() :
+{
+	Token dispositionType;
+}
+{
+	dispositionType=<ATOKEN>
+	{
+		this.dispositionType = dispositionType.image;
+	}
+	( ";" parameter() )*
+}
+
+void parameter() :
+{
+	Token attrib;
+	String val;
+}
+{
+	attrib=<ATOKEN> "=" val=value()
+	{
+		paramNames.add(attrib.image);
+		paramValues.add(val);
+	}
+}
+
+String value() :
+{Token t;}
+{
+(	t=<ATOKEN>
+|   t=<DIGITS>
+|	t=<QUOTEDSTRING>
+)
+	{ return t.image; }
+}
+
+
+
+SPECIAL_TOKEN :
+{
+ 	< WS: ( [" ", "\t"] )+ >
+}
+
+TOKEN_MGR_DECLS :
+{
+	// Keeps track of how many levels of comment nesting
+	// we've encountered.  This is only used when the 2nd
+	// level is reached, for example ((this)), not (this).
+	// This is because the outermost level must be treated
+	// specially anyway, because the outermost ")" has a
+	// different token type than inner ")" instances.
+	static int commentNest;
+}
+
+MORE :
+{
+	// starts a comment
+	"(" : INCOMMENT
+}
+
+<INCOMMENT>
+SKIP :
+{
+	// ends a comment
+	< COMMENT: ")" > : DEFAULT
+	// if this is ever changed to not be a SKIP, need
+	// to make sure matchedToken.token = token.toString()
+	// is called.
+}
+
+<INCOMMENT>
+MORE :
+{
+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|	"(" { commentNest = 1; } : NESTED_COMMENT
+|	< <ANY>>
+}
+
+<NESTED_COMMENT>
+MORE :
+{
+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|	"(" { ++commentNest; }
+|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
+|	< <ANY>>
+}
+
+
+
+// QUOTED STRINGS
+
+MORE :
+{
+	"\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING
+}
+
+<INQUOTEDSTRING>
+MORE :
+{
+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|	< (~["\"", "\\"])+ >
+}
+
+<INQUOTEDSTRING>
+TOKEN :
+{
+	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT
+}
+
+
+TOKEN :
+{
+	< DIGITS: ( ["0"-"9"] )+ >
+}
+
+TOKEN :
+{
+	< ATOKEN: ( ~[" ", "\t", "(", ")", "<", ">", "@", ",", ";", ":", "\\", "\"", "/", "[", "]", "?", "="] )+ >
+}
+
+
+// GLOBALS
+
+<*>
+TOKEN :
+{
+	< #QUOTEDPAIR: "\\" <ANY> >
+|	< #ANY: ~[] >
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contentdisposition/ParseException.java b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contentdisposition/ParseException.java
new file mode 100644
index 0000000..3a4db50
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contentdisposition/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.contentdisposition.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contenttype/ContentTypeParser.jj b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contenttype/ContentTypeParser.jj
new file mode 100644
index 0000000..6c4fefb
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contenttype/ContentTypeParser.jj
@@ -0,0 +1,229 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+

+/**

+ * RFC2045 Content-Type parser.

+ *

+ * Created 10/2/2004

+ * by Joe Cheng <code@joecheng.com>

+ */

+

+options {

+	STATIC=false;

+	LOOKAHEAD=1;

+	JDK_VERSION = "1.5";

+	OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";

+	//DEBUG_PARSER=true;

+	//DEBUG_TOKEN_MANAGER=true;

+}

+

+PARSER_BEGIN(ContentTypeParser)

+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+package org.apache.james.mime4j.field.contenttype.parser;

+

+import java.util.List;

+import java.util.ArrayList;

+

+public class ContentTypeParser {

+

+	private String type;

+	private String subtype;

+	private List<String> paramNames = new ArrayList<String>();

+	private List<String> paramValues = new ArrayList<String>();

+

+	public String getType() { return type; }

+	public String getSubType() { return subtype; }

+	public List<String> getParamNames() { return paramNames; }

+	public List<String> getParamValues() { return paramValues; }

+

+    public static void main(String args[]) throws ParseException {

+	while (true) {

+	    try {

+		ContentTypeParser parser = new ContentTypeParser(System.in);

+	    	parser.parseLine();

+	    } catch (Exception x) {

+		x.printStackTrace();

+		return;

+	    }

+	}

+    }

+}

+

+PARSER_END(ContentTypeParser)

+

+void parseLine() :

+{}

+{

+	parse() ["\r"] "\n"

+}

+

+void parseAll() :

+{}

+{

+	parse() <EOF>

+}

+

+void parse() :

+{

+	Token type;

+	Token subtype;

+}

+{

+	type=<ATOKEN> "/" subtype=<ATOKEN>

+	{

+		this.type = type.image;

+		this.subtype = subtype.image;

+	}

+	( ";" parameter() )*

+}

+

+void parameter() :

+{

+	Token attrib;

+	String val;

+}

+{

+	attrib=<ATOKEN> "=" val=value()

+	{

+		paramNames.add(attrib.image);

+		paramValues.add(val);

+	}

+}

+

+String value() :

+{Token t;}

+{

+(	t=<ATOKEN>

+|   t=<DIGITS>

+|	t=<QUOTEDSTRING>

+)

+	{ return t.image; }

+}

+

+

+

+SPECIAL_TOKEN :

+{

+ 	< WS: ( [" ", "\t"] )+ >

+}

+

+TOKEN_MGR_DECLS :

+{

+	// Keeps track of how many levels of comment nesting

+	// we've encountered.  This is only used when the 2nd

+	// level is reached, for example ((this)), not (this).

+	// This is because the outermost level must be treated

+	// specially anyway, because the outermost ")" has a

+	// different token type than inner ")" instances.

+	static int commentNest;

+}

+

+MORE :

+{

+	// starts a comment

+	"(" : INCOMMENT

+}

+

+<INCOMMENT>

+SKIP :

+{

+	// ends a comment

+	< COMMENT: ")" > : DEFAULT

+	// if this is ever changed to not be a SKIP, need

+	// to make sure matchedToken.token = token.toString()

+	// is called.

+}

+

+<INCOMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { commentNest = 1; } : NESTED_COMMENT

+|	< <ANY>>

+}

+

+<NESTED_COMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { ++commentNest; }

+|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }

+|	< <ANY>>

+}

+

+

+

+// QUOTED STRINGS

+

+MORE :

+{

+	"\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING

+}

+

+<INQUOTEDSTRING>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	< (~["\"", "\\"])+ >

+}

+

+<INQUOTEDSTRING>

+TOKEN :

+{

+	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT

+}

+

+

+TOKEN :

+{

+	< DIGITS: ( ["0"-"9"] )+ >

+}

+

+TOKEN :

+{

+	< ATOKEN: ( ~[" ", "\t", "(", ")", "<", ">", "@", ",", ";", ":", "\\", "\"", "/", "[", "]", "?", "="] )+ >

+}

+

+

+// GLOBALS

+

+<*>

+TOKEN :

+{

+	< #QUOTEDPAIR: "\\" <ANY> >

+|	< #ANY: ~[] >

+}

diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contenttype/ParseException.java b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contenttype/ParseException.java
new file mode 100644
index 0000000..6c81d19
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/contenttype/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.contenttype.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/datetime/DateTimeParser.jj b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/datetime/DateTimeParser.jj
new file mode 100644
index 0000000..44cb416
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/datetime/DateTimeParser.jj
@@ -0,0 +1,344 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+

+/**

+ * RFC2822 date parser.

+ *

+ * Created 9/28/2004

+ * by Joe Cheng <code@joecheng.com>

+ */

+

+options {

+	STATIC=false;

+	LOOKAHEAD=1;

+	JDK_VERSION = "1.5";

+	OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";

+	//DEBUG_PARSER=true;

+	//DEBUG_TOKEN_MANAGER=true;

+}

+

+PARSER_BEGIN(DateTimeParser)

+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+package org.apache.james.mime4j.field.datetime.parser;

+

+import org.apache.james.mime4j.field.datetime.DateTime;

+

+public class DateTimeParser {

+    private static final boolean ignoreMilitaryZoneOffset = true;

+

+    public static void main(String args[]) throws ParseException {

+		while (true) {

+		    try {

+				DateTimeParser parser = new DateTimeParser(System.in);

+		    	parser.parseLine();

+		    } catch (Exception x) {

+				x.printStackTrace();

+				return;

+		    }

+		}

+    }

+

+    private static int parseDigits(Token token) {

+        return Integer.parseInt(token.image, 10);

+    }

+

+    private static int getMilitaryZoneOffset(char c) {

+        if (ignoreMilitaryZoneOffset)

+            return 0;

+

+        c = Character.toUpperCase(c);

+

+        switch (c) {

+            case 'A': return 1;

+            case 'B': return 2;

+            case 'C': return 3;

+            case 'D': return 4;

+            case 'E': return 5;

+            case 'F': return 6;

+            case 'G': return 7;

+            case 'H': return 8;

+            case 'I': return 9;

+            case 'K': return 10;

+            case 'L': return 11;

+            case 'M': return 12;

+

+            case 'N': return -1;

+            case 'O': return -2;

+            case 'P': return -3;

+            case 'Q': return -4;

+            case 'R': return -5;

+            case 'S': return -6;

+            case 'T': return -7;

+            case 'U': return -8;

+            case 'V': return -9;

+            case 'W': return -10;

+            case 'X': return -11;

+            case 'Y': return -12;

+

+            case 'Z': return 0;

+            default: return 0;

+        }

+    }

+

+    private static class Time {

+        private int hour;

+        private int minute;

+        private int second;

+        private int zone;

+

+        public Time(int hour, int minute, int second, int zone) {

+            this.hour = hour;

+            this.minute = minute;

+            this.second = second;

+            this.zone = zone;

+        }

+

+        public int getHour() { return hour; }

+        public int getMinute() { return minute; }

+        public int getSecond() { return second; }

+        public int getZone() { return zone; }

+    }

+

+    private static class Date {

+        private String year;

+        private int month;

+        private int day;

+

+        public Date(String year, int month, int day) {

+            this.year = year;

+            this.month = month;

+            this.day = day;

+        }

+

+        public String getYear() { return year; }

+        public int getMonth() { return month; }

+        public int getDay() { return day; }

+    }

+}

+

+PARSER_END(DateTimeParser)

+

+DateTime parseLine() :

+{DateTime dt;}

+{

+	dt=date_time() ["\r"] "\n"

+	{ return dt; }

+}

+

+DateTime parseAll() :

+{DateTime dt;}

+{

+	dt=date_time() <EOF>

+	{ return dt; }

+}

+

+DateTime date_time() :

+{Date d; Time t;}

+{

+	[ day_of_week() "," ]

+	d=date()

+	t=time()

+	{

+	    return new DateTime(

+	            d.getYear(),

+	            d.getMonth(),

+	            d.getDay(),

+	            t.getHour(),

+	            t.getMinute(),

+	            t.getSecond(),

+	            t.getZone());    // time zone offset

+	}

+}

+

+String day_of_week() :

+{}

+{

+(    "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"

+)

+    { return token.image; }

+}

+

+Date date() :

+{int d, m; String y;}

+{

+    d=day() m=month() y=year()

+    { return new Date(y, m, d); }

+}

+

+int day() :

+{Token t;}

+{

+    t=<DIGITS> { return parseDigits(t); }

+}

+

+int month() :

+{}

+{

+    "Jan" { return 1; }

+|   "Feb" { return 2; }

+|   "Mar" { return 3; }

+|   "Apr" { return 4; }

+|   "May" { return 5; }

+|   "Jun" { return 6; }

+|   "Jul" { return 7; }

+|   "Aug" { return 8; }

+|   "Sep" { return 9; }

+|   "Oct" { return 10; }

+|   "Nov" { return 11; }

+|   "Dec" { return 12; }

+}

+

+String year() :

+{Token t;}

+{

+    t=<DIGITS> { return t.image; }

+}

+

+Time time() :

+{int h, m, s=0, z;}

+{

+    h=hour() ":" m=minute() [ ":" s=second() ] z=zone()

+    { return new Time(h, m, s, z); }

+}

+

+int hour() :

+{Token t;}

+{

+    t=<DIGITS> { return parseDigits(t); }

+}

+

+int minute() :

+{Token t;}

+{

+    t=<DIGITS> { return parseDigits(t); }

+}

+

+int second() :

+{Token t;}

+{

+    t=<DIGITS> { return parseDigits(t); }

+}

+

+int zone() :

+{ Token t, u; int z; }

+{

+(    t=< OFFSETDIR: ["+", "-"] > u=<DIGITS> { z=parseDigits(u)*(t.image.equals("-") ? -1 : 1); }

+|   z=obs_zone()

+)

+    { return z; }

+}

+

+int obs_zone() :

+{Token t; int z;}

+{

+(   "UT"  { z=0; }

+|   "GMT" { z=0; }

+|   "EST" { z=-5; }

+|   "EDT" { z=-4; }

+|   "CST" { z=-6; }

+|   "CDT" { z=-5; }

+|   "MST" { z=-7; }

+|   "MDT" { z=-6; }

+|   "PST" { z=-8; }

+|   "PDT" { z=-7; }

+|   t=< MILITARY_ZONE: ["A"-"I","a"-"i","K"-"Z","k"-"z"] > { z=getMilitaryZoneOffset(t.image.charAt(0)); }

+)

+    { return z * 100; }

+}

+

+SPECIAL_TOKEN :

+{

+ 	< WS: ( [" ", "\t"] )+ >

+}

+

+TOKEN_MGR_DECLS :

+{

+	// Keeps track of how many levels of comment nesting

+	// we've encountered.  This is only used when the 2nd

+	// level is reached, for example ((this)), not (this).

+	// This is because the outermost level must be treated

+	// specially anyway, because the outermost ")" has a

+	// different token type than inner ")" instances.

+	static int commentNest;

+}

+

+MORE :

+{

+	// starts a comment

+	"(" : INCOMMENT

+}

+

+<INCOMMENT>

+SKIP :

+{

+	// ends a comment

+	< COMMENT: ")" > : DEFAULT

+	// if this is ever changed to not be a SKIP, need

+	// to make sure matchedToken.token = token.toString()

+	// is called.

+}

+

+<INCOMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { commentNest = 1; } : NESTED_COMMENT

+|	< <ANY>>

+}

+

+<NESTED_COMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { ++commentNest; }

+|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }

+|	< <ANY>>

+}

+

+TOKEN :

+{

+    < DIGITS: ( ["0"-"9"] )+ >

+}

+

+// GLOBALS

+

+<*>

+TOKEN :

+{

+	< #QUOTEDPAIR: "\\" <ANY> >

+|	< #ANY: ~[] >

+}

diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/datetime/ParseException.java b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/datetime/ParseException.java
new file mode 100644
index 0000000..bf8ce67
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/datetime/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.datetime.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/language/ContentLanguageParser.jj b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/language/ContentLanguageParser.jj
new file mode 100644
index 0000000..958fe30
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/language/ContentLanguageParser.jj
@@ -0,0 +1,209 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+options {

+  static=false;

+  JDK_VERSION = "1.5";

+  OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";

+}

+

+PARSER_BEGIN(ContentLanguageParser)

+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+package org.apache.james.mime4j.field.language.parser;
+

+import java.util.ArrayList;

+import java.util.List;

+

+public class ContentLanguageParser {

+	private List<String> languages = new ArrayList<String>();

+	

+	/**

+	 * Parses the input into a list of language tags.

+	 * @return list of language tag Strings

+	 */

+	public List<String> parse() throws ParseException {

+		try {

+			return doParse();

+		} catch (TokenMgrError e) {

+			// An issue with the TOKENiser 

+			// but it's not polite to throw an Error

+			// when executing on a server

+			throw new ParseException(e);

+		}

+	}

+}

+PARSER_END(ContentLanguageParser)

+

+private List<String> doParse() :

+{

+}

+{

+	language() ( "," language() )*

+	{return languages;}

+}

+

+String language() :

+{

+	Token token;

+	StringBuffer languageTag = new StringBuffer();

+	String result;

+}

+{

+	token = <ALPHA> 

+			{

+				languageTag.append(token.image);

+			}

+		( 

+		"-" 

+// This keeps TOKENising simple

+				token = <ALPHA> 

+					{

+						languageTag.append('-');

+						languageTag.append(token.image);

+					}

+				|

+				token = <ALPHANUM> 

+					{

+						languageTag.append('-');

+						languageTag.append(token.image);

+					}

+		)*

+	

+	{

+		result = languageTag.toString();

+		languages.add(result);

+		return result;

+	}

+}

+

+

+

+

+SPECIAL_TOKEN :

+{

+ 	< WS: ( [" ", "\t", "\r", "\n"] )+ >

+}

+

+TOKEN_MGR_DECLS :

+{

+	// Keeps track of how many levels of comment nesting

+	// we've encountered.  This is only used when the 2nd

+	// level is reached, for example ((this)), not (this).

+	// This is because the outermost level must be treated

+	// specially anyway, because the outermost ")" has a

+	// different token type than inner ")" instances.

+	int commentNest;

+}

+

+

+MORE :

+{

+	// starts a comment

+	"(" : INCOMMENT

+}

+

+<INCOMMENT>

+SKIP :

+{

+	// ends a comment

+	< COMMENT: ")" > : DEFAULT

+	// if this is ever changed to not be a SKIP, need

+	// to make sure matchedToken.token = token.toString()

+	// is called.

+}

+

+<INCOMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { commentNest = 1; } : NESTED_COMMENT

+|	< <ANY>>

+}

+

+<NESTED_COMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { ++commentNest; }

+|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }

+|	< <ANY>>

+}

+// QUOTED STRINGS

+

+MORE :

+{

+	"\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING

+}

+

+<INQUOTEDSTRING>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	< (~["\"", "\\"])+ >

+}

+

+<INQUOTEDSTRING>

+TOKEN :

+{

+	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT

+}

+

+TOKEN :

+{

+	< DIGITS: ( ["0"-"9"] )+ >

+}

+

+TOKEN :

+{

+	< ALPHA: ( ["a"-"z"] | ["A"-"Z"] )+ >

+}

+

+TOKEN :

+{

+	<ALPHANUM : (  ["0"-"9"] |  ["a"-"z"] | ["A"-"Z"] )+>

+}

+

+TOKEN :

+{

+	< DOT: "." >

+}

+

+<*>

+TOKEN :

+{

+	< #QUOTEDPAIR: "\\" <ANY> >

+|	< #ANY: ~[] >

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/language/ParseException.java b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/language/ParseException.java
new file mode 100644
index 0000000..7768564
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/language/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.language.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/mimeversion/MimeVersionParser.jj b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/mimeversion/MimeVersionParser.jj
new file mode 100644
index 0000000..39b6bb5
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/mimeversion/MimeVersionParser.jj
@@ -0,0 +1,176 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+options {

+  static=false;

+  JDK_VERSION = "1.5";

+  OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";

+}

+

+PARSER_BEGIN(MimeVersionParser)

+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+package org.apache.james.mime4j.field.mimeversion.parser;
+

+public class MimeVersionParser {

+	public static final int INITIAL_VERSION_VALUE = -1;

+	private int major=INITIAL_VERSION_VALUE;

+	private int minor=INITIAL_VERSION_VALUE;

+	

+	public int getMinorVersion() {

+		return minor;

+	}

+	

+	public int getMajorVersion() {

+		return major;

+	}

+}

+PARSER_END(MimeVersionParser)

+

+

+void parseLine() :

+{}

+{

+	parse() ["\r"] "\n"

+}

+

+void parseAll() :

+{}

+{

+	parse() <EOF>

+}

+

+void parse() :

+{

+	Token major;

+	Token minor;

+}

+{

+	major=<DIGITS> <DOT> minor=<DIGITS>

+	{

+		try {

+			this.major = Integer.parseInt(major.image);

+			this.minor = Integer.parseInt(minor.image);

+		} catch (NumberFormatException e) {

+			throw new ParseException(e.getMessage());

+		}

+	}

+}

+

+SPECIAL_TOKEN :

+{

+ 	< WS: ( [" ", "\t", "\r", "\n"] )+ >

+}

+

+TOKEN_MGR_DECLS :

+{

+	// Keeps track of how many levels of comment nesting

+	// we've encountered.  This is only used when the 2nd

+	// level is reached, for example ((this)), not (this).

+	// This is because the outermost level must be treated

+	// specially anyway, because the outermost ")" has a

+	// different token type than inner ")" instances.

+	int commentNest;

+}

+

+

+MORE :

+{

+	// starts a comment

+	"(" : INCOMMENT

+}

+

+<INCOMMENT>

+SKIP :

+{

+	// ends a comment

+	< COMMENT: ")" > : DEFAULT

+	// if this is ever changed to not be a SKIP, need

+	// to make sure matchedToken.token = token.toString()

+	// is called.

+}

+

+<INCOMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { commentNest = 1; } : NESTED_COMMENT

+|	< <ANY>>

+}

+

+<NESTED_COMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { ++commentNest; }

+|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }

+|	< <ANY>>

+}

+// QUOTED STRINGS

+

+MORE :

+{

+	"\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING

+}

+

+<INQUOTEDSTRING>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	< (~["\"", "\\"])+ >

+}

+

+<INQUOTEDSTRING>

+TOKEN :

+{

+	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT

+}

+

+TOKEN :

+{

+	< DIGITS: ( ["0"-"9"] )+ >

+}

+

+TOKEN :

+{

+	< DOT: "." >

+}

+

+<*>

+TOKEN :

+{

+	< #QUOTEDPAIR: "\\" <ANY> >

+|	< #ANY: ~[] >

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/mimeversion/ParseException.java b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/mimeversion/ParseException.java
new file mode 100644
index 0000000..a7b748c
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/mimeversion/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.mimeversion.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/structured/ParseException.java b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/structured/ParseException.java
new file mode 100644
index 0000000..26c936d
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/structured/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.structured.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj
new file mode 100644
index 0000000..6bf7c94
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javacc/org/apache/james/mime4j/field/structured/StructuredFieldParser.jj
@@ -0,0 +1,227 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+options {

+  static=false;

+  JDK_VERSION = "1.5";

+  OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc";

+  //DEBUG_PARSER = true;

+  //DEBUG_TOKEN_MANAGER = true;

+}

+

+PARSER_BEGIN(StructuredFieldParser)

+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+package org.apache.james.mime4j.field.structured.parser;

+

+/**

+ * Parses generic structure fields.

+ * Unfolds and removes comments.

+ */

+public class StructuredFieldParser {

+	

+	private boolean preserveFolding = false;

+	

+	/**

+	 * Should the \r\n folding sequence be preserved?

+	 */

+	public boolean isFoldingPreserved() {

+		return preserveFolding;

+	}

+	

+	/**

+	 * Sets whether the \r\n folding sequence should be preserved.

+	 */

+	public void setFoldingPreserved(boolean preserveFolding) {

+		this.preserveFolding =  preserveFolding;

+	}

+	

+	/**

+	 * Unfolds the input and removes comments.

+	 * @return unfolded header value with comments removed

+	 */

+	public String parse() throws ParseException {

+		try {

+			return doParse();

+		} catch (TokenMgrError e) {

+			// An issue with the TOKENiser 

+			// but it's not polite to throw an Error

+			// when executing on a server

+			throw new ParseException(e);

+		}

+	}

+}

+PARSER_END(StructuredFieldParser)

+

+private String doParse() :

+{

+	Token t;

+	StringBuffer buffer = new StringBuffer(50);

+	boolean whitespace = false;

+	boolean first = true;

+}

+{

+	( 

+		t = <CONTENT> 

+			{

+				if (first) {

+					first = false;

+				} else if (whitespace) {

+					buffer.append(" ");

+					whitespace = false;

+				}

+				buffer.append(t.image);

+			}

+		| 

+		t = <STRING_CONTENT>

+			{

+				buffer.append(t.image);

+			}

+		|

+		t = <QUOTEDSTRING>

+			{

+				if (first) {

+					first = false;

+				} else if (whitespace) {

+					buffer.append(" ");

+					whitespace = false;

+				}

+				buffer.append(t.image);

+			}

+		|

+		t = <FOLD>

+			{

+				if (preserveFolding) buffer.append("\r\n");

+			}

+		|

+		t = <WS> 

+			{

+				whitespace = true;	

+			}

+	)*

+	{return buffer.toString();}

+}

+

+TOKEN_MGR_DECLS :

+{

+	// Keeps track of how many levels of comment nesting

+	// we've encountered.  This is only used when the 2nd

+	// level is reached, for example ((this)), not (this).

+	// This is because the outermost level must be treated

+	// specially anyway, because the outermost ")" has a

+	// different token type than inner ")" instances.

+	int commentNest;

+}

+

+

+SKIP :

+{

+	// starts a comment

+	"(" : INCOMMENT

+}

+

+<INCOMMENT> SKIP :

+{

+	// ends a comment

+	")" : DEFAULT

+	// if this is ever changed to not be a SKIP, need

+	// to make sure matchedToken.token = token.toString()

+	// is called.

+}

+

+<INCOMMENT> SKIP :

+{

+  "(" { commentNest = 1; } : NESTED_COMMENT

+}

+

+<INCOMMENT> SKIP :

+{

+  <~[ "(", ")" ]>

+}

+

+<NESTED_COMMENT> SKIP:

+{

+	"(" { ++commentNest; System.out.println("+++ COMMENT NEST=" + commentNest);}

+|	")" { --commentNest; System.out.println("+++ COMMENT NEST=" + commentNest); if (commentNest == 0) SwitchTo(INCOMMENT); }

+}

+

+<NESTED_COMMENT> SKIP :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+}

+

+<NESTED_COMMENT> SKIP:

+{

+	<~[ "(", ")" ]>

+}

+

+// QUOTED STRINGS

+

+SKIP :

+{

+	"\"" : INQUOTEDSTRING

+}

+

+<INQUOTEDSTRING> MORE :

+{

+	< <QUOTEDPAIR> > { image.deleteCharAt(image.length() - 2); }

+}

+

+<INQUOTEDSTRING> TOKEN :

+{

+	< STRING_CONTENT : (~["\"", "\\", "\r"])+ >

+	// Preserve line break within quotes but not trailing white space

+|	< FOLD: "\r\n" ( [" ", "\t"] )* >

+|	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT

+}

+

+<DEFAULT>

+TOKEN :

+{

+ 	< WS: ( [" ", "\t", "\r", "\n"] )+ >

+}

+

+<DEFAULT>

+TOKEN :

+{

+	< CONTENT: (~[" ", "\t", "\r", "\n", "(", "\""])+ >

+}

+

+<*>

+TOKEN :

+{

+	< #QUOTEDPAIR: "\\" <ANY> >

+|	< #ANY: (~[])+ >

+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/javadoc/overview.html b/apache-mime4j-0.6/src/main/javadoc/overview.html
new file mode 100644
index 0000000..87a17bc
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/javadoc/overview.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.    
+-->
+<HTML>
+  <HEAD>
+    <TITLE>API Overview</TITLE>
+  </HEAD>
+  <BODY>
+<p><b>Mime4j</b> provides a parser, <a href="org/apache/james/mime4j/parser/MimeStreamParser.html">MimeStreamParser</a>, for e-mail message streams in plain rfc822 and MIME format and a <a href="org/apache/james/mime4j/message/Message.html">Message</a> class used to build a tree representation of an e-mail message.</p>
+
+<p>The parser uses a callback mechanism to report parsing events such as the start of an entity header the start of a body, etc. If you are familiar with the SAX XML parser interface you should have no problem getting started with mime4j.</p>
+<p>The parser only deals with the structure of the message stream. It won't do any decoding of base64 or quoted-printable encoded header fields and bodies. This is intentional - the parser should only provide the most basic functionality needed to build more complex parsers. However, mime4j does include facilities to decode bodies and fields and the Message class described below handles decoding of fields and bodies transparently.</p>
+<p>The parser has been designed to be extremely tolerant against messages violating the standards. It has been tested using a large corpus (>5000) of e-mail messages. As a benchmark the widely used perl MIME::Tools parser has been used. mime4j and MIME:Tools rarely differ (<25 in those 5000). When they do (which only occurs for illegally formatted spam messages) we think mime4j does a better job.</p>
+<p><b>Mime4j</b> can also be used to build a tree representation of an e-mail message using the <a href="org/apache/james/mime4j/message/Message.html">Message</a> class. Using this facility mime4j automatically handles the decoding of fields and bodies and uses temporary files for large attachments. This representation is similar to the representation constructed by the JavaMail API:s but is more tolerant to messages violating the standards.</p>
+  </BODY>
+</HTML>
diff --git a/apache-mime4j-0.6/src/main/jjtree/org/apache/james/mime4j/field/address/AddressListParser.jjt b/apache-mime4j-0.6/src/main/jjtree/org/apache/james/mime4j/field/address/AddressListParser.jjt
new file mode 100644
index 0000000..c1e5d92
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/jjtree/org/apache/james/mime4j/field/address/AddressListParser.jjt
@@ -0,0 +1,358 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+

+/**

+ * RFC2822 address list parser.

+ *

+ * Created 9/17/2004

+ * by Joe Cheng <code@joecheng.com>

+ */

+

+options {

+	STATIC=false;

+	LOOKAHEAD=1;

+	JDK_VERSION = "1.5";

+	VISITOR=true;

+	MULTI=true;

+	NODE_SCOPE_HOOK=true;

+	NODE_EXTENDS="org.apache.james.mime4j.field.address.parser.BaseNode"; 

+	//DEBUG_PARSER=true;

+	//DEBUG_TOKEN_MANAGER=true;

+}

+

+PARSER_BEGIN(AddressListParser)

+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+package org.apache.james.mime4j.field.address.parser;

+

+public class AddressListParser {

+    public static void main(String args[]) throws ParseException {

+        while (true) {

+            try {

+                AddressListParser parser = new AddressListParser(System.in);

+                parser.parseLine();

+                ((SimpleNode) parser.jjtree.rootNode()).dump("> ");

+            } catch (Exception x) {

+                x.printStackTrace();

+                return;

+            }

+        }

+    }

+

+    public ASTaddress_list parseAddressList() throws ParseException {

+        try {

+            parseAddressList0();

+            return (ASTaddress_list) jjtree.rootNode();

+        } catch (TokenMgrError tme) {

+            throw new ParseException(tme.getMessage());

+        }

+    }

+

+    public ASTaddress parseAddress() throws ParseException {

+        try {

+            parseAddress0();

+            return (ASTaddress) jjtree.rootNode();

+        } catch (TokenMgrError tme) {

+            throw new ParseException(tme.getMessage());

+        }

+    }

+

+    public ASTmailbox parseMailbox() throws ParseException {

+        try {

+            parseMailbox0();

+            return (ASTmailbox) jjtree.rootNode();

+        } catch (TokenMgrError tme) {

+            throw new ParseException(tme.getMessage());

+        }

+    }

+

+    void jjtreeOpenNodeScope(Node n) {

+        ((SimpleNode) n).firstToken = getToken(1);

+    }

+

+    void jjtreeCloseNodeScope(Node n) {

+        ((SimpleNode) n).lastToken = getToken(0);

+    }

+}

+

+PARSER_END(AddressListParser)

+

+void parseLine() #void :

+{}

+{

+	address_list() ["\r"] "\n"

+}

+

+void parseAddressList0() #void :

+{}

+{

+	address_list() <EOF>

+}

+

+void parseAddress0() #void :

+{}

+{

+	address() <EOF>

+}

+

+void parseMailbox0() #void :

+{}

+{

+	mailbox() <EOF>

+}

+

+void address_list() :

+{}

+{

+	[ address() ]

+	(

+		","

+		[ address() ]

+	)*

+}

+

+void address() :

+{}

+{

+	LOOKAHEAD(2147483647)

+	addr_spec()

+|	angle_addr()

+|	( phrase() (group_body() | angle_addr()) )

+}

+

+void mailbox() :

+{}

+{

+	LOOKAHEAD(2147483647)

+	addr_spec()

+|	angle_addr()

+|	name_addr()

+}

+

+void name_addr() :

+{}

+{

+	phrase() angle_addr()

+}

+

+void group_body() :

+{}

+{

+	":"

+	[ mailbox() ]

+	(

+		","

+		[ mailbox() ]

+	)*

+	";"

+}

+

+void angle_addr() :

+{}

+{

+	"<" [ route() ] addr_spec() ">"

+}

+

+void route() :

+{}

+{

+	"@" domain() ( (",")* "@" domain() )* ":"

+}

+

+void phrase() :

+{}

+{

+(	<DOTATOM>

+|	<QUOTEDSTRING>

+)+

+}

+

+void addr_spec() :

+{}

+{

+	( local_part() "@" domain() )

+}

+

+void local_part() :

+{ Token t; }

+{

+	( t=<DOTATOM> | t=<QUOTEDSTRING> )

+	(	[t="."]

+		{

+			if ( t.kind == AddressListParserConstants.QUOTEDSTRING || t.image.charAt(t.image.length() - 1) != '.')

+				throw new ParseException("Words in local part must be separated by '.'");

+		}

+		(	t=<DOTATOM> | t=<QUOTEDSTRING> )

+	)*

+}

+

+void domain() :

+{ Token t; }

+{

+	(	t=<DOTATOM>

+		(	[t="."]

+			{

+				if (t.image.charAt(t.image.length() - 1) != '.')

+					throw new ParseException("Atoms in domain names must be separated by '.'");

+			}

+			t=<DOTATOM>

+		)*

+	)

+|	<DOMAINLITERAL>

+}

+

+SPECIAL_TOKEN :

+{

+ 	< WS: ( [" ", "\t"] )+ >

+}

+

+TOKEN :

+{

+	< #ALPHA: ["a" - "z", "A" - "Z"] >

+|	< #DIGIT: ["0" - "9"] >

+|	< #ATEXT: ( <ALPHA> | <DIGIT>

+			  | "!" | "#" | "$" | "%"

+			  | "&" | "'" | "*" | "+"

+			  | "-" | "/" | "=" | "?"

+			  | "^" | "_" | "`" | "{"

+			  | "|" | "}" | "~"

+			  )>

+|	< DOTATOM: <ATEXT> ( <ATEXT> | "." )* >

+}

+

+TOKEN_MGR_DECLS :

+{

+	// Keeps track of how many levels of comment nesting

+	// we've encountered.  This is only used when the 2nd

+	// level is reached, for example ((this)), not (this).

+	// This is because the outermost level must be treated

+	// specially anyway, because the outermost ")" has a 

+	// different token type than inner ")" instances.

+	static int commentNest;

+}

+

+MORE :

+{

+	// domain literal

+	"[" : INDOMAINLITERAL

+}

+

+<INDOMAINLITERAL>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	< ~["[", "]", "\\"] >

+}

+

+<INDOMAINLITERAL>

+TOKEN :

+{

+	< DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT

+}

+

+MORE :

+{

+	// starts a comment

+	"(" : INCOMMENT

+}

+

+<INCOMMENT>

+SKIP :

+{

+	// ends a comment

+	< COMMENT: ")" > : DEFAULT

+	// if this is ever changed to not be a SKIP, need

+	// to make sure matchedToken.token = token.toString()

+	// is called.

+}

+

+<INCOMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { commentNest = 1; } : NESTED_COMMENT

+|	< <ANY>>

+}

+

+<NESTED_COMMENT>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	"(" { ++commentNest; }

+|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }

+|	< <ANY>>

+}

+

+

+// QUOTED STRINGS

+

+MORE :

+{

+	"\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING

+}

+

+<INQUOTEDSTRING>

+MORE :

+{

+	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }

+|	< (~["\"", "\\"])+ >

+}

+

+<INQUOTEDSTRING>

+TOKEN :

+{

+	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT

+}

+

+// GLOBALS

+

+<*>

+TOKEN :

+{

+	< #QUOTEDPAIR: "\\" <ANY> >

+|	< #ANY: ~[] >

+}

+

+// ERROR!

+/*

+

+<*>

+TOKEN :

+{

+	< UNEXPECTED_CHAR: <ANY> >

+}

+

+*/
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/main/jjtree/org/apache/james/mime4j/field/address/ParseException.java b/apache-mime4j-0.6/src/main/jjtree/org/apache/james/mime4j/field/address/ParseException.java
new file mode 100644
index 0000000..ab46e29
--- /dev/null
+++ b/apache-mime4j-0.6/src/main/jjtree/org/apache/james/mime4j/field/address/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/
+package org.apache.james.mime4j.field.address.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ *   extends org.apache.james.mime4j.field.ParseException
+ *   added serialVersionUID
+ *   added constructor ParseException(Throwable)
+ *   default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.field.ParseException {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.  The boolean
+   * flag "specialConstructor" is also set to true to indicate that
+   * this constructor was used to create this object.
+   * This constructor calls its super class with the empty string
+   * to force the "toString" method of parent class "Throwable" to
+   * print the error message in the form:
+   *     ParseException: <result of getMessage>
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super("");
+    specialConstructor = true;
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super("Cannot parse field");
+    specialConstructor = false;
+  }
+
+  public ParseException(Throwable cause) {
+    super(cause);
+    specialConstructor = false;
+  }
+
+  public ParseException(String message) {
+    super(message);
+    specialConstructor = false;
+  }
+
+  /**
+   * This variable determines which constructor was used to create
+   * this object and thereby affects the semantics of the
+   * "getMessage" method (see below).
+   */
+  protected boolean specialConstructor;
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * This method has the standard behavior when this object has been
+   * created using the standard constructors.  Otherwise, it uses
+   * "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser), then this method is called during the printing
+   * of the final stack trace, and hence the correct error message
+   * gets displayed.
+   */
+  public String getMessage() {
+    if (!specialConstructor) {
+      return super.getMessage();
+    }
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(eol).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += add_escapes(tok.image);
+      tok = tok.next; 
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    retval += "." + eol;
+    if (expectedTokenSequences.length == 1) {
+      retval += "Was expecting:" + eol + "    ";
+    } else {
+      retval += "Was expecting one of:" + eol + "    ";
+    }
+    retval += expected.toString();
+    return retval;
+  }
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected String eol = System.getProperty("line.separator", "\n");
+ 
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  protected String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case 0 :
+              continue;
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
diff --git a/apache-mime4j-0.6/src/site/apt/status.apt b/apache-mime4j-0.6/src/site/apt/status.apt
new file mode 100644
index 0000000..cc6d027
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/apt/status.apt
@@ -0,0 +1,39 @@
+
+~~   Licensed to the Apache Software Foundation (ASF) under one
+~~   or more contributor license agreements.  See the NOTICE file
+~~   distributed with this work for additional information
+~~   regarding copyright ownership.  The ASF licenses this file
+~~   to you under the Apache License, Version 2.0 (the
+~~   "License"); you may not use this file except in compliance
+~~   with the License.  You may obtain a copy of the License at
+~~
+~~     http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~   Unless required by applicable law or agreed to in writing,
+~~   software distributed under the License is distributed on an
+~~   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~   KIND, either express or implied.  See the License for the
+~~   specific language governing permissions and limitations
+~~   under the License.
+
+ -------------
+ Status
+ -------------
+
+{Status}
+
+    The 0.4 release brought a number of significant improvements in terms of 
+    supported capabilities, flexibility and performance.
+
+    The 0.5 release addressed a number of important issues discovered since
+    the 0.4 release. In particular it improved Mime4j ability to deal with
+    malformed data streams including those intentionally crafted to cause 
+    excessive CPU and memory utilization that can lead to DoS conditions.
+
+    The 0.6 release brought another round of API enhancements and performance 
+    optimizations. As of this release Mime4j requires a Java 1.5 compatible 
+    runtime.    
+    
+    The next release will be version 0.7. The main focus of the development 
+    efforts will be on optimization of MIME header parsing and further 
+    enhancement of DOM capabilities.
diff --git a/apache-mime4j-0.6/src/site/apt/usage.apt b/apache-mime4j-0.6/src/site/apt/usage.apt
new file mode 100644
index 0000000..181ce50
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/apt/usage.apt
@@ -0,0 +1,191 @@
+

+~~   Licensed to the Apache Software Foundation (ASF) under one

+~~   or more contributor license agreements.  See the NOTICE file

+~~   distributed with this work for additional information

+~~   regarding copyright ownership.  The ASF licenses this file

+~~   to you under the Apache License, Version 2.0 (the

+~~   "License"); you may not use this file except in compliance

+~~   with the License.  You may obtain a copy of the License at

+~~

+~~     http://www.apache.org/licenses/LICENSE-2.0

+~~

+~~   Unless required by applicable law or agreed to in writing,

+~~   software distributed under the License is distributed on an

+~~   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+~~   KIND, either express or implied.  See the License for the

+~~   specific language governing permissions and limitations

+~~   under the License.

+

+ -------------

+ Usage

+ -------------

+

+{Usage}

+

+  Mime4j provides two different API's: An event based API by using

+  the {{{apidocs/org/apache/james/mime4j/parser/MimeStreamParser.html}

+  MimeStreamParser}}. Alternatively, you may use the iterative

+  API, which is available through the

+  {{{apidocs/org/apache/james/mime4j/parser/MimeTokenStream.html}

+  MimeTokenStream}}. In terms of speed, you should not note

+  any differences.

+

+  * {{{#Token Streams}Token Streams}}

+

+  * {{{#Sample Token Stream}Sample Token Stream}}

+

+  * {{{#Event Handlers}Event Handlers}}

+

+  * {{{#Sample Event Stream}Sample Event Stream}}

+

+{Token Streams}

+

+  The iterative approach is using the class

+  {{{apidocs/org/apache/james/mime4j/parser/MimeTokenStream.html}

+  MimeTokenStream}}. Here's an example, how you could use

+  the token stream:

+

+--------------------------------------------------------------------

+  MimeTokenStream stream = new MimeTokenStream();

+  stream.parse(new BufferedInputStream(new FileInputStream("mime.msg")));

+  for (int state = stream.getState();

+       state != MimeTokenStream.T_END_OF_STREAM;

+       state = stream.next()) {

+    switch (state) {

+      case MimeTokenStream.T_BODY:

+        System.out.println("Body detected, contents = "

+          + stream.getInputStream() + ", header data = "

+          + stream.getBodyDescriptor());

+        break;

+      case MimeTokenStream.T_FIELD:

+        System.out.println("Header field detected: "

+          + stream.getField());

+        break;

+      case MimeTokenStream.T_START_MULTIPART:

+        System.out.println("Multipart message detexted,"

+          + " header data = "

+          + stream.getBodyDescriptor());

+      ...

+    }

+  }

+--------------------------------------------------------------------  

+

+  The token stream provides a set of tokens. Tokens are identified

+  by a state. Most states are simply event indicators, with no

+  additional data available. However, there are some states,

+  which provide additional data. For example, the state

+  <<<T_BODY>>>, which indicates that an actual body is available,

+  If you note this state, then you may ask for the bodies contents,

+  which are provided through the <<<getInputStream()>>> method,

+  or you might ask for the header data by invoking

+  <<<getBodyDescriptor()>>>.

+

+{Sample Token Stream}

+

+  The following sample should give you a rough idea of the order,

+  in which you'll receive tokens:

+

+--------------------------------------------------------------------  

+  T_START_MESSAGE

+      T_START_HEADER

+          T_FIELD

+          T_FIELD

+          ...

+      T_END_HEADER

+      T_START_MULTIPART

+          T_PREAMBLE

+          T_START_BODYPART

+              T_START_HEADER

+                  T_FIELD

+                  T_FIELD

+                  ...

+              T_END_HEADER

+              T_BODY

+          T_END_BODYPART

+          T_START_BODYPART

+              T_START_HEADER

+                  T_FIELD

+                  T_FIELD

+                  ...

+              T_END_HEADER

+              T_BODY

+          T_END_BODYPART

+          T_EPILOGUE

+      T_END_MULTIPART

+   T_END_MESSAGE

+--------------------------------------------------------------------  

+

+  The example shows a multipart message with two parts.

+

+{Event Handlers}

+

+  The event based API requires, that you provide an event handler,

+  which receives events. The event handler is an object, which

+  implements the {{{apidocs/org/apache/james/mime4j/parser/ContentHandler.html}

+  ContentHandler}} interface. Here's an example, how you could

+  implement an event handler:

+

+--------------------------------------------------------------------  

+  public class MyContentHandler extends org.apache.james.mime4j.parser.ContentHandler {

+      public body(BodyDescriptor bd, InputStream is)

+              throws MimeException, IOException {

+          System.out.println("Body detected, contents = "

+              + is + ", header data = " + bd);

+      }

+      public void field(String fieldData) throws MimeException {

+          System.out.println("Header field detected: "

+              + fieldData);

+      }

+      public void startMultipart(BodyDescriptor bd) throws MimeException {

+          System.out.println("Multipart message detexted, header data = "

+              + bd);

+      }

+      ...

+  }

+--------------------------------------------------------------------  

+

+  A little bit of additional code allows us to create an example, which

+  is functionally equivalent to the example from the section on

+  {{{#Token Streams}Token Streams}}:

+

+--------------------------------------------------------------------  

+  ContentHandler handler = new MyContentHandler();

+  MimeStreamParser parser = new MimeStreamParser();

+  parser.setContentHandler(handler);

+  parser.parse(new BufferedInputStream(new FileInputStream("mime.msg")));

+--------------------------------------------------------------------  

+

+{Sample Event Stream}

+

+  Like above for tokens, we provide an additional example, which

+  demonstrates the typical order of events that you have to expect:

+

+--------------------------------------------------------------------

+  startMessage()

+      startHeader()

+          field(...)

+          field(...)

+          ...

+      endHeader()

+      startMultipart()

+          preamble(...)

+          startBodyPart()

+              startHeader()

+                  field(...)

+                  field(...)

+                  ...

+              endHeader()

+              body()

+          endBodyPart()

+          startBodyPart()

+              startHeader()

+                  field(...)

+                  field(...)

+                  ...

+              endHeader()

+              body()

+          endBodyPart()

+          epilogue(...)

+      endMultipart()

+  endMessage()

+--------------------------------------------------------------------  

diff --git a/apache-mime4j-0.6/src/site/resources/images/asf-logo-reduced.gif b/apache-mime4j-0.6/src/site/resources/images/asf-logo-reduced.gif
new file mode 100644
index 0000000..93cc102
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/resources/images/asf-logo-reduced.gif
Binary files differ
diff --git a/apache-mime4j-0.6/src/site/resources/images/james-mime4j-logo.gif b/apache-mime4j-0.6/src/site/resources/images/james-mime4j-logo.gif
new file mode 100644
index 0000000..9d565f2
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/resources/images/james-mime4j-logo.gif
Binary files differ
diff --git a/apache-mime4j-0.6/src/site/site.xml b/apache-mime4j-0.6/src/site/site.xml
new file mode 100644
index 0000000..491071f
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/site.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--

+  Licensed to the Apache Software Foundation (ASF) under one

+  or more contributor license agreements.  See the NOTICE file

+  distributed with this work for additional information

+  regarding copyright ownership.  The ASF licenses this file

+  to you under the Apache License, Version 2.0 (the

+  "License"); you may not use this file except in compliance

+  with the License.  You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+

+  Unless required by applicable law or agreed to in writing,

+  software distributed under the License is distributed on an

+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+  KIND, either express or implied.  See the License for the

+  specific language governing permissions and limitations

+  under the License.    

+-->

+<project name="James mime4j">
+  <bannerLeft>
+    <name>JAMES Mime4J</name>
+    <src>images/james-mime4j-logo.gif</src>
+    <href>http://james.apache.org/</href>
+  </bannerLeft>
+  <bannerRight>

+    <name>The Apache Software Foundation</name>

+    <src>images/asf-logo-reduced.gif</src>

+    <href>http://www.apache.org/index.html</href>

+  </bannerRight> 

+  <body>
+    <menu name="mime4j">
+      <item name="Overview" href="/index.html"/>
+      <item name="Status" href="/status.html"/>
+      <item name="Example" href="/samples.html"/>

+      <item name="Usage" href="/usage.html"/>
+      <item name="Start" href="/start/index.html" collapse="true">
+        <item name="Download" href="/start/download.html" collapse="true"/>

+        <item name="Build" href="/start/build.html" collapse="true"/>
+      </item>
+    </menu>
+    
+    ${reports}

+    

+    <menu name="Related Projects">

+    	<item name="httpmime" href="http://hc.apache.org/httpcomponents-client/httpmime/index.html" />

+    </menu>
+  </body>
+</project>
diff --git a/apache-mime4j-0.6/src/site/xdoc/index.xml b/apache-mime4j-0.6/src/site/xdoc/index.xml
new file mode 100644
index 0000000..1f9c247
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/xdoc/index.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+
+ -->
+<document>
+    <properties>
+        <title>Mime4j</title>
+    </properties>
+    <body>
+        <section name="Mime4j">
+            <p>
+                Apache Mime4j is developed by the 
+                <a href="http://james.apache.org/">Apache James</a> team but now has a
+                dedicated <a href="http://james.apache.org/mail.html#Mime4j">mailing list</a>.
+            </p>
+            <p> mime4j provides a parser, 
+                <a href="apidocs/org/apache/james/mime4j/parser/MimeStreamParser.html">
+                    <code>MimeStreamParser</code>
+                </a>, for e-mail message streams in plain rfc822 and MIME
+                format. The parser uses a callback mechanism to report parsing
+                events such as the start of an entity header, the start of a
+                body, etc. If you are familiar with the <a
+                href="http://www.saxproject.org/">SAX</a> XML parser interface
+                you should have no problem getting started with mime4j. </p>
+            <p> The parser only deals with the structure of the message stream.
+                It won't do any decoding of base64 or quoted-printable encoded
+                header fields and bodies. This is intentional - the parser
+                should only provide the most basic functionality needed to build
+                more complex parsers. However, mime4j does include facilities to
+                decode bodies and fields and the <code>Message</code> class
+                described below handles decoding of fields and bodies
+                transparently. </p>
+            <p> The parser has been designed to be extremely tolerant against
+                messages violating the standards. It has been tested using a
+                large corpus (&gt;5000) of e-mail messages. As a benchmark
+                the widely used perl <code>MIME::Tools</code>
+                parser has been used. mime4j and MIME:Tools rarely differ
+                (&lt;25 in those 5000). When they do (which only occurs
+                for illegally formatted spam messages) we think mime4j does a
+                better job. </p>
+            <p> mime4j can also be used to build a tree representation of an
+                e-mail message using the 
+                <a href="apidocs/org/apache/james/mime4j/message/Message.html">
+                    <code>Message</code>
+                </a> class. Using this facility mime4j automatically handles the
+                decoding of fields and bodies and uses temporary files for large
+                attachments. This representation is similar to the
+                representation constructed by the JavaMail API:s but is more
+                tolerant to messages violating the standards. </p>
+        </section>
+    </body>
+</document>
diff --git a/apache-mime4j-0.6/src/site/xdoc/navigation.xml b/apache-mime4j-0.6/src/site/xdoc/navigation.xml
new file mode 100644
index 0000000..8353cb3
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/xdoc/navigation.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+
+ -->
+<project name="mime4j">
+    <title>mime4j - the Java stream based MIME message parser</title>
+    <body>
+        <links>
+            <item name="Home Page" href="http://www.mime4j.org/"/>
+            <item name="Browse Source Code" href="http://svn.apache.org/viewcvs.cgi/james/mime4j/trunk/"/>
+        </links>        
+        <menu name="Overview">
+            <!--<item name="Features" href="/features.html"/>-->
+            <item name="News and Status" href="/status.html"/>
+            <item name="Getting Started" href="/start/index.html" collapse="true">
+                <item name="Download" href="/start/download.html"/>
+                <item name="Build" href="/start/build.html"/>
+            </item>
+        </menu>
+        <menu name="Documentation">
+<!--            <item name="Samples" href="/samples.html"/>-->
+            <item name="API docs (Javadoc)" href="/apidocs/"/>
+        </menu>
+    </body>
+</project>
diff --git a/apache-mime4j-0.6/src/site/xdoc/samples.xml b/apache-mime4j-0.6/src/site/xdoc/samples.xml
new file mode 100755
index 0000000..ebf1371
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/xdoc/samples.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+
+ -->
+<document>
+    <properties>
+        <title>Samples</title>
+    </properties>
+    <body>
+        <section name="Samples">
+            <p>
+            The Mime4j distribution includes samples
+            which demonstrate how the library could be used. This section
+            gives you a short review of those samples. For more information
+            you should download the distribution and study the sample sources.
+            The samples are in the <code>examples/</code> sub-directory.
+            </p>
+            <table>
+                    <tr>
+                        <th>Sample</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>
+                            <code>org.apache.james.mime4j.samples.tree.MessageTree</code>
+                        </td>
+                        <td>Displays a tree of the contents of a
+                            Mime4j <code>Message</code> object in a Swing GUI.
+                            To try it out run
+                            <blockquote>
+                             <code>java org.apache.james.mime4j.samples.tree.MessageTree path/to/message.msg</code>
+                            </blockquote>
+                            The output is very useful if
+                            you want the study the structure of MIME messages.
+                            </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <code>org.apache.james.mime4j.samples.transform.TransformMessage</code>
+                        </td>
+                        <td>Illustrate how to transform a message into another message without 
+                            modifying the original.
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <code>org.apache.james.mime4j.samples.dom.TextPlainMessage</code>
+                        </td>
+                        <td>Illustrate the use of Mime4j DOM API. This example generates a message 
+                        very similar to the one from 
+                        <a href="http://www.rfc-editor.org/rfc/rfc5322.txt">RFC 5322</a>
+                        Appendix A.1.1.
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <code>org.apache.james.mime4j.samples.dom.MultipartMessage</code>
+                        </td>
+                        <td>Illustrate the use of Mime4j DOM API. This example creates a
+                            multipart/mixed message that consists of a text/plain and an image/png
+                            part. The image is created on the fly; a similar technique can be used
+                            to create PDF or XML attachments, for example.
+                        </td>
+                    </tr>
+               <!--      <tr>
+                        <td>
+                            <code>org.apache.james.mime4j.samples.sax.Mime2Sax</code>
+                        </td>
+                        <td></td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <code>org.apache.james.mime4j.samples.pgp.PGPSignatureVerifier</code>
+                        </td>
+                        <td></td>
+                    </tr> -->
+                </table>
+        </section>
+    </body>
+</document>
diff --git a/apache-mime4j-0.6/src/site/xdoc/start/build.xml b/apache-mime4j-0.6/src/site/xdoc/start/build.xml
new file mode 100644
index 0000000..6faabf5
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/xdoc/start/build.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+
+ -->
+<document>
+    <properties>
+        <title>Building mime4j</title>
+    </properties>
+    <body>
+        <section name="Building mime4j">
+            <subsection name="Using a Stable Release">
+            <p> Go to the <a href="http://james.apache.org/download.cgi">download 
+              pages</a> and download the most recent
+                release in your preferred format, either
+                <code>james-mime4j-x.y-src.tar.gz</code> or <code>james-mime4j-x.y-src.zip</code>.
+                Extracting the archived sources will create the directory
+                <code>james-mime4j-x.y/</code>.</p>
+            </subsection>
+            <subsection name="Checking Out From Subversion">
+                <p>
+                    Issue the following commands in a shell:
+                    <blockquote>
+                        <code>svn checkout http://svn.apache.org/repos/asf/james/mime4j/trunk james-mime4j</code><br/>
+                    </blockquote>
+                </p>
+            </subsection>
+            <subsection name="Download and Install Maven">
+                <p> You will need to download and install <a
+                    href="http://maven.apache.org/">Maven</a> before building
+                    the sources. The build has been tested with version 2.0 of
+                    Maven so use this or a later version if possible. </p>
+                <p> One of the main differences between Maven and plain ant is
+                    that Maven manages external dependencies for your projects
+                    and (at least in theory) you should no longer have to store
+                    third-party jar files in your source code tree. It maintains a local
+                    repository of versioned libraries and shares them between
+                    your Maven projects. If it can't find the necessary files
+                    there it will attempt to download them from the main Maven
+                    repository at www.ibiblio.org/maven. So to use the Maven
+                    build, you need to have a network connection available for
+                    the inital download of the project dependencies. </p>
+            </subsection>
+            <subsection name="Building the mime4j Jar">
+                <p> Once Maven has been installed, building the project should
+                    be as simple as typing <blockquote>
+                        <code>cd james-mime4j-x.y/ (cd james-mime4j/ if sources come from
+                            Subversion)<br/>mvn package</code>
+                    </blockquote> from the command line. Maven will
+                    automatically run all test cases for you and create the
+                    jar file in the <code>target</code> directory. 
+                </p>
+                <p>
+                    To install the jar into your local Maven repository run <blockquote>
+                        <code>mvn install</code></blockquote>
+                </p>
+                <p>
+                    To generate an Eclipse project from the sources run <blockquote>
+                        <code>mvn eclipse:eclipse</code></blockquote>

+                </p>
+                <p>
+                  <strong>NOTE!</strong> Mime4j uses <a href="https://javacc.dev.java.net/">JavaCC</a> to generate parsers for
+                  header fields. If you're using an old version of maven eclipse pluing
+                  <code>mvn eclipse:eclipse</code> could have problems  
+                  generating proper source folders for the JavaCC generated code.
+                  After running <code>mvn eclipse:eclipse</code> you must manually
+                  add <code>target/generated-sources/javacc</code> and 
+                  <code>target/generated-sources/jjtree</code> as source folders
+                  under <em>Project -&gt; Properties</em> in Eclipse.
+                </p>
+                <p>
+                    For more information on using
+                    Maven, have a look at the <a
+                        href="http://maven.apache.org/">Maven web site</a>. </p>
+            </subsection>
+        </section>
+    </body>
+</document>
diff --git a/apache-mime4j-0.6/src/site/xdoc/start/download.xml b/apache-mime4j-0.6/src/site/xdoc/start/download.xml
new file mode 100644
index 0000000..5be2f44
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/xdoc/start/download.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+
+ -->
+<document>
+    <properties>
+        <title>Downloading mime4j</title>
+    </properties>
+    <body>
+        <section name="Downloading mime4j">
+            <p> Go to the <a href="http://james.apache.org/download.cgi">download 
+              pages</a> and download the most recent
+                release in your preferred format, either
+                <code>james-mime4j-x.y.tar.gz</code> or <code>james-mime4j-x.y.zip</code>.
+                Extracting the archive will create the directory
+                <code>james-mime4j-x.y/</code> which contains the mime4j jar file and
+                the API docs.</p>
+        </section>
+    </body>
+</document>
diff --git a/apache-mime4j-0.6/src/site/xdoc/start/index.xml b/apache-mime4j-0.6/src/site/xdoc/start/index.xml
new file mode 100644
index 0000000..f87221d
--- /dev/null
+++ b/apache-mime4j-0.6/src/site/xdoc/start/index.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- 
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+
+ -->
+<document>
+    <properties>
+        <title>Getting Started with mime4j</title>
+    </properties>
+    <body>
+        <section name="Getting Started with mime4j">
+            <subsection name="Overview of the Getting Started Documentation">
+                <table>
+                    <tr>
+                        <th>Document</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>
+                            <a href="download.html">Download</a>
+                        </td>
+                        <td> Before you can start using mime4j, you'll have to
+                            download the distribution to your system (unless you
+                            plan on building the project from source). This
+                            document provides links to the various distributions
+                            available. </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <a href="build.html">Building mime4j</a>
+                        </td>
+                        <td>
+				Describes how to build mime4j from the sources. 
+                        </td>
+                    </tr>
+                </table>
+            </subsection>
+        </section>
+    </body>
+</document>
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/EncodeUtils.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/EncodeUtils.java
new file mode 100644
index 0000000..c568035
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/EncodeUtils.java
@@ -0,0 +1,111 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+
+public class EncodeUtils {
+    
+    public static final int MASK = 0x3F;
+    public static final int FIRST_MASK = MASK << 18; 
+    public static final int SECOND_MASK = MASK << 12; 
+    public static final int THIRD_MASK = MASK << 6; 
+    public static final int FORTH_MASK = MASK; 
+    
+    public static final byte[] ENCODING = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+        'O', 'P' ,'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+        'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+        '4', '5', '6', '7', '8', '9', '+', '/'};
+    
+    public static final void main(String[] args) throws Exception {
+        byte[] bytes = {(byte) 0, (byte) 128, (byte) 0};
+        System.out.println(new String(toBase64(bytes)));
+        System.out.println(new String(toBase64("Hello, World".getBytes())));
+        System.out.println(new String(toBase64("Monday".getBytes())));
+        System.out.println(new String(toBase64("M\u00F6nchengladbach\r\n".getBytes("ISO-8859-1"))));
+    }
+    
+    public static byte[] toBase64(byte[] in) {
+        int inputLength = in.length;
+        int outputLength = (int) Math.floor((4*inputLength) / 3f) + 3;
+        outputLength = outputLength + 2 * (int) Math.floor(outputLength / 76f);
+        byte[] results = new byte[outputLength];
+        int inputIndex = 0;
+        int outputIndex = 0;
+        while (inputLength - inputIndex > 2) {
+            int one = (toInt(in[inputIndex++]) << 16);
+            int two = (toInt(in[inputIndex++]) << 8);
+            int three = toInt(in[inputIndex++]);
+            int quantum = one | two | three;
+            int index = (quantum & FIRST_MASK) >> 18;
+            outputIndex = setResult(results, outputIndex, ENCODING[index]);
+            index = (quantum & SECOND_MASK) >> 12;
+            outputIndex = setResult(results, outputIndex, ENCODING[index]);
+            index = (quantum & THIRD_MASK) >> 6;
+            outputIndex = setResult(results, outputIndex, ENCODING[index]);
+            index = (quantum & FORTH_MASK);
+            outputIndex = setResult(results, outputIndex, ENCODING[index]);
+        }
+        
+        switch (inputLength - inputIndex) {
+            case 1:
+                int quantum = in[inputIndex++] << 16;
+                int index = (quantum & FIRST_MASK) >> 18;
+                outputIndex = setResult(results, outputIndex, ENCODING[index]);
+                index = (quantum & SECOND_MASK) >> 12;
+                outputIndex = setResult(results, outputIndex, ENCODING[index]);
+                outputIndex = setResult(results, outputIndex, (byte) '=');
+                outputIndex = setResult(results, outputIndex, (byte) '=');
+                break;
+                
+            case 2:
+                quantum = (in[inputIndex++] << 16) + (in[inputIndex++] << 8);
+                index = (quantum & FIRST_MASK) >> 18;
+                outputIndex = setResult(results, outputIndex, ENCODING[index]);
+                index = (quantum & SECOND_MASK) >> 12;
+                outputIndex = setResult(results, outputIndex, ENCODING[index]);
+                index = (quantum & THIRD_MASK) >> 6;
+                outputIndex = setResult(results, outputIndex, ENCODING[index]);
+                outputIndex = setResult(results, outputIndex, (byte) '=');
+                break;
+        }
+        
+        return results;
+    }
+
+    private static int toInt(byte b) {
+        return 255 & b;
+    }
+
+
+    private static int setResult(byte[] results, int outputIndex, byte value) {
+        results[outputIndex++] = value;
+        outputIndex = checkLineLength(results, outputIndex);
+        return outputIndex;
+    }
+
+
+    private static int checkLineLength(byte[] results, int outputIndex) {
+        if (outputIndex == 76 || outputIndex > 76 && (outputIndex - 2*Math.floor(outputIndex/76f - 1)) % 76 == 0) {
+            results[outputIndex++] = '\r';
+            results[outputIndex++] = '\n';
+        }
+        return outputIndex;
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/ExampleMail.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/ExampleMail.java
new file mode 100644
index 0000000..3d140bf
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/ExampleMail.java
@@ -0,0 +1,691 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j;
+
+import java.nio.charset.Charset;
+import java.util.Locale;
+
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class ExampleMail {
+    
+    public static final String MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MULTIPART_MIXED = "--4.66920160910299\r\n" + 
+            "Content-Type: image/gif\r\n" + 
+            "Content-Transfer-Encoding: base64\r\n" + 
+            "MIME-Version: 1.0\r\n" + 
+            "Content-ID: 238478934723847238947892374\r\n" + 
+            "Content-Description: Bogus Image Data\r\n" + 
+            "\r\n" + 
+            "ABCDFEGHIJKLMNO\r\n" + 
+            "\r\n" + 
+            "--4.66920160910299\r\n" + 
+            "Content-Type: message/rfc822\r\n" + 
+            "\r\n" + 
+            "From: Timothy Tayler <timothy@example.org>\r\n" + 
+            "To: John Smith <john@example.org>\r\n" + 
+            "Date: Sat, 16 Feb 2008 12:00:00 +0000 (GMT)\r\n" + 
+            "Subject: Another Example Email\r\n" + 
+            "Content-Type: multipart/mixed;boundary=2.50290787509\r\n" + 
+            "\r\n" + 
+            "Yet another preamble\r\n" + 
+            "\r\n" + 
+            "--2.50290787509\r\n" + 
+            "Content-Type: text/plain\r\n" + 
+            "\r\n" + 
+            "Rhubard AND Custard!\r\n" + 
+            "\r\n" + 
+            "--2.50290787509\r\n" + 
+            "Content-Type: multipart/alternative;boundary=3.243F6A8885A308D3\r\n" + 
+            "\r\n" + 
+            "--3.243F6A8885A308D3\r\n" + 
+            "Content-Type: text/plain\r\n" + 
+            "\r\n" + 
+            "Rhubard?Custard?\r\n" + 
+            "\r\n" + 
+            "--3.243F6A8885A308D3\r\n" + 
+            "\r\n" + 
+            "Content-Type: text/richtext\r\n" + 
+            "\r\n" + 
+            "Rhubard?Custard?\r\n" + 
+            "\r\n" + 
+            "--3.243F6A8885A308D3--\r\n" + 
+            "\r\n" + 
+            "--2.50290787509--\r\n" + 
+            "\r\n" + 
+            "--4.66920160910299--";
+
+    public static final String MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MAIL = "From: Timothy Tayler <timothy@example.org>\r\n" + 
+            "To: Samual Smith <samual@example.org>\r\n" + 
+            "Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)\r\n" + 
+            "Subject: A Multipart Alternative Email\r\n" + 
+            "Content-Type: multipart/alternative;boundary=42\r\n" + 
+            "\r\n" + 
+            "This message has a premable\r\n" + 
+            "\r\n" + 
+            "--42\r\n" + 
+            "Content-Type: text/plain; charset=US-ASCII\r\n" + 
+            "\r\n" + 
+            "Custard!\r\n" + 
+            "\r\n" + 
+            "--42\r\n" + 
+            "Content-Type: application/octet-stream\r\n" + 
+            "\r\n" + 
+            "CUSTARDCUSTARDCUSTARD\r\n" + 
+            "\r\n" + 
+            "--42--\r\n";
+
+    public static final String MIME_MULTIPART_EMBEDDED_MESSAGES_BODY = "Start with a preamble\r\n" + 
+            "\r\n" + 
+            "--1729\r\n" + 
+            "Content-Type: text/plain; charset=US-ASCII\r\n" + 
+            "\r\n" + 
+            "Rhubarb!\r\n" + 
+            "\r\n" + 
+            "--1729\r\n" + 
+            "Content-Type: application/octet-stream\r\n" + 
+            "Content-Transfer-Encoding: base64\r\n" + 
+            "\r\n" + 
+            "987654321AHPLA\r\n" + 
+            "\r\n" + 
+            "--1729\r\n" + 
+            "Content-Type: message/rfc822\r\n" + 
+            "\r\n" + 
+            MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MAIL + 
+            "\r\n" + 
+            "--1729\r\n" + 
+            "Content-Type: multipart/mixed; boundary=4.66920160910299\r\n" + 
+            "\r\n" + 
+            MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MULTIPART_MIXED + "\r\n" +
+            "--1729--\r\n" + 
+            "\r\n";
+    
+    public static final String MD5_CONTENT = "Q2hlY2sgSW50ZWdyaXR5IQ==";
+    public static final String CONTENT_DESCRIPTION = "Blah blah blah";
+    public static final String CONTENT_ID = "<f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>";
+    public static final Charset US_ASCII = CharsetUtil.US_ASCII;
+    public static final Charset LATIN1 = CharsetUtil.ISO_8859_1;
+    
+    public static final String MIME_MULTIPART_EMBEDDED_MESSAGES = 
+        "From: Timothy Tayler <timothy@example.org>\r\n" + 
+        "To: Samual Smith <samual@example.org>\r\n" + 
+        "Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)\r\n" + 
+        "Subject: A Multipart Email\r\n" + 
+        "Content-Type: multipart/mixed;boundary=1729\r\n" + 
+        "\r\n" + 
+        MIME_MULTIPART_EMBEDDED_MESSAGES_BODY; 
+
+    
+    public static final String MULTIPART_WITH_CONTENT_LOCATION = 
+        "From: Timothy Tayler <timothy@example.org>\r\n" +
+        "To: Samual Smith <samual@example.org>\r\n" +
+        "Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)\r\n" +
+        "Subject: A Multipart Email With Content-Location\r\n" +
+        "Content-Type: multipart/mixed;boundary=1729\r\n\r\n" +
+        "Start with a preamble\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: application/xhtml+xml\r\n" +
+        "Content-Location: relative/url\r\n\r\n" +
+        "<!DOCTYPE html\r\n" +
+        "PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\r\n" +
+        "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n" +
+        "<html><head><title>Rhubarb</title></head><body>Rhubarb!</body></html>\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: text/plain; charset=US-ASCII\r\n" +
+        "Content-Location: http://www.example.org/absolute/rhubard.txt\r\n\r\n" +
+        "Rhubarb!\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: text/html; charset=US-ASCII\r\n\r\n" +
+        "<html><head><title>Rhubarb</title></head><body>Rhubarb!</body></html>\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: text/plain; charset=US-ASCII\r\n" +
+        "Content-Location: (Some comment) \"http://www.example.org/absolute/comments/rhubard.txt\"(Another comment)\r\n\r\n" +
+        "Rhubarb!\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: text/html; charset=US-ASCII\r\n" +
+        "Content-Location:\"http://www.example.org/this/\r\n" +
+        "          is/a/very/long/url/split/\r\n" +
+        "          over/two/lines/\"\r\n\r\n" +
+        "<html><head><title>Rhubarb</title></head><body>Rhubarb!</body></html>\r\n" +
+        "\r\n--1729--\r\n" +
+        "This is the epilogue\r\n";
+    
+    public static final String MULTIPART_WITH_BINARY_ATTACHMENTS = 
+        "Return-Path: <robertburrelldonkin@blueyonder.co.uk>\r\n" +
+        "Received: (qmail 18554 invoked from network); 25 May 2008 14:38:53 -0000\r\n" +
+        "Received: from unknown (HELO p3presmtp01-16.prod.phx3.secureserver.net)\r\n" +
+        "        ([208.109.80.165]) (envelope-sender <rdonkin-owner@locus.apache.org>) by\r\n" +
+        "        smtp20-01.prod.mesa1.secureserver.net (qmail-1.03) with SMTP for\r\n" +
+        "        <asf@xmlmapt.org>; 25 May 2008 14:38:53 -0000\r\n" +
+        "Received: (qmail 9751 invoked from network); 25 May 2008 14:38:53 -0000\r\n" +
+        "Received: from minotaur.apache.org ([140.211.11.9]) (envelope-sender\r\n" +
+        "        <rdonkin-owner@locus.apache.org>) by\r\n" +
+        "        p3presmtp01-16.prod.phx3.secureserver.net (qmail-ldap-1.03) with SMTP for\r\n" +
+        "        <asf@xmlmapt.org>; 25 May 2008 14:38:50 -0000\r\n" +
+        "Received: (qmail 46768 invoked by uid 1289); 25 May 2008 14:38:46 -0000\r\n" +
+        "Delivered-To: rdonkin@locus.apache.org\r\n" +
+        "Received: (qmail 46763 invoked from network); 25 May 2008 14:38:46 -0000\r\n" +
+        "Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by\r\n" +
+        "        minotaur.apache.org with SMTP; 25 May 2008 14:38:46 -0000\r\n" +
+        "Received: (qmail 61275 invoked by uid 500); 25 May 2008 14:38:48 -0000\r\n" +
+        "Delivered-To: apmail-rdonkin@apache.org\r\n" +
+        "Delivered-To: rob@localhost\r\n" +
+        "Delivered-To: rob@localhost\r\n" +
+        "Received: (qmail 61272 invoked by uid 99); 25 May 2008 14:38:48 -0000\r\n" +
+        "Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)\r\n" +
+        "        by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008 07:38:48 -0700\r\n" +
+        "X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS\r\n" +
+        "X-Spam-Check-By: apache.org\r\n" +
+        "Received-SPF: pass (athena.apache.org: domain of\r\n" +
+        "        robertburrelldonkin@blueyonder.co.uk designates 195.188.213.5 as permitted\r\n" +
+        "        sender)\r\n" +
+        "Received: from [195.188.213.5] (HELO smtp-out2.blueyonder.co.uk)\r\n" +
+        "        (195.188.213.5) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008\r\n" +
+        "        14:38:00 +0000\r\n" +
+        "Received: from [172.23.170.140] (helo=anti-virus02-07) by\r\n" +
+        "        smtp-out2.blueyonder.co.uk with smtp (Exim 4.52) id 1K0HMV-00087e-HY for\r\n" +
+        "        rdonkin@apache.org; Sun, 25 May 2008 15:38:15 +0100\r\n" +
+        "Received: from [82.38.65.6] (helo=[10.0.0.27]) by\r\n" +
+        "        asmtp-out5.blueyonder.co.uk with esmtpa (Exim 4.52) id 1K0HMU-0001A2-3q for\r\n" +
+        "        rdonkin@apache.org; Sun, 25 May 2008 15:38:14 +0100\r\n" +
+        "Subject: This is an example of a multipart mixed email with image content\r\n" +
+        "From: Robert Burrell Donkin <robertburrelldonkin@blueyonder.co.uk>\r\n" +
+        "To: Robert Burrell Donkin <rdonkin@apache.org>\r\n" +
+        "Content-Type: multipart/mixed; boundary=\"=-tIdGYVstQJghyEDATnJ+\"\r\n" +
+        "Date: Sun, 25 May 2008 15:38:13 +0100\r\n" +
+        "Message-Id: <1211726293.5772.10.camel@localhost>\r\n" +
+        "Mime-Version: 1.0\r\n" +
+        "X-Mailer: Evolution 2.12.3 \r\n" +
+        "X-Virus-Checked: Checked by ClamAV on apache.org\r\n" +
+        "X-Nonspam: None\r\n" +
+        "X-fetched-from: mail.xmlmapt.org\r\n" +
+        "X-Evolution-Source: imap://rob@thebes/\r\n" +
+        "\r\n" +
+        "\r\n" +
+        "--=-tIdGYVstQJghyEDATnJ+\r\n" +
+        "Content-Type: text/plain\r\n" +
+        "Content-Transfer-Encoding: 7bit\r\n" +
+        "\r\n" +
+        "Licensed to the Apache Software Foundation (ASF) under one\r\n" +
+        "or more contributor license agreements.  See the NOTICE file\r\n" +
+        "distributed with this work for additional information\r\n" +
+        "regarding copyright ownership.  The ASF licenses this file\r\n" +
+        "to you under the Apache License, Version 2.0 (the\r\n" +
+        "\"License\"); you may not use this file except in compliance\r\n" +
+        "with the License.  You may obtain a copy of the License at\r\n" +
+        "\r\n" +
+        "    http://www.apache.org/licenses/LICENSE-2.0\r\n" +
+        " \r\n" +
+        "Unless required by applicable law or agreed to in writing,\r\n" +
+        "software distributed under the License is distributed on an\r\n" +
+        "\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\n" +
+        "KIND, either express or implied.  See the License for the\r\n" +
+        "specific language governing permissions and limitations\r\n" +
+        "under the License.\r\n" +
+        " \r\n" +
+        "\r\n" +
+        "--=-tIdGYVstQJghyEDATnJ+\r\n" +
+        "Content-Disposition: attachment; filename=blob.png;\r\n   modification-date=\"Sun, 21 Jun 2008 15:32:18 +0000\"; " +
+        "creation-date=\"Sat, 20 Jun 2008 10:15:09 +0000\"; read-date=\"Mon, 22 Jun 2008 12:08:56 +0000\";size=10234;\r\n" +
+        "Content-Type: image/png; name=blob.png\r\n" +
+        "Content-Transfer-Encoding: base64\r\n" +
+        "\r\n" +
+        "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL\r\n" +
+        "EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo\r\n" +
+        "IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ\r\n" +
+        "/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE\r\n" +
+        "E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF\r\n" +
+        "iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp\r\n" +
+        "rQAAAABJRU5ErkJggg==\r\n" +
+        "\r\n" +
+        "--=-tIdGYVstQJghyEDATnJ+\r\n" +
+        "Content-Disposition: attachment; filename=blob.png\r\n" +
+        "Content-Type: image/png; name=blob.png\r\n" +
+        "Content-Transfer-Encoding: base64\r\n" +
+        "\r\n" +
+        "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL\r\n" +
+        "EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo\r\n" +
+        "IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ\r\n" +
+        "/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE\r\n" +
+        "E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF\r\n" +
+        "iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp\r\n" +
+        "rQAAAABJRU5ErkJggg==\r\n" +
+        "\r\n" +
+        "--=-tIdGYVstQJghyEDATnJ+\r\n" +
+        "Content-Disposition: attachment; filename=rhubarb.txt\r\n" +
+        "Content-Type: text/plain; name=rhubarb.txt; charset=us-ascii\r\n" +
+        "Content-Language: en, en-US, en-CA\r\n" +
+        "Content-Transfer-Encoding: quoted-printable\r\n" +
+        "\r\n" +
+        "Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=\r\n" +
+        "barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=\r\n" +
+        "b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=\r\n" +
+        "hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=\r\n" +
+        "arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=\r\n" +
+        " Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=\r\n" +
+        "ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=\r\n" +
+        "rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =\r\n" +
+        "Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=\r\n" +
+        "barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=\r\n" +
+        "b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=\r\n" +
+        "hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=\r\n" +
+        "arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=\r\n" +
+        " Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=\r\n" +
+        "ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=\r\n" +
+        "rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =\r\n" +
+        "Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=\r\n" +
+        "barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=\r\n" +
+        "b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=\r\n" +
+        "hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=\r\n" +
+        "arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=\r\n" +
+        " Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=\r\n" +
+        "ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=\r\n" +
+        "rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =\r\n" +
+        "Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=\r\n" +
+        "barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=\r\n" +
+        "b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=\r\n" +
+        "hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=\r\n" +
+        "arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=\r\n" +
+        " Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=\r\n" +
+        "ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=\r\n" +
+        "rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =\r\n" +
+        "Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=\r\n" +
+        "barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=\r\n" +
+        "b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=\r\n" +
+        "hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=\r\n" +
+        "arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=\r\n" +
+        " Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=\r\n" +
+        "ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=\r\n" +
+        "rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =\r\n" +
+        "Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb\r\n" +
+        "\r\n" +
+        "--=-tIdGYVstQJghyEDATnJ+--\r\n";
+    
+    public static final String ONE_PART_MIME_ASCII_BODY = "A single part MIME mail.\r\n";
+
+    public static final String RFC822_SIMPLE_BODY = "This is a very simple email.\r\n";
+    
+    public static final String ONE_PART_MIME_8859_BODY = "M\u00F6nchengladbach\r\n";
+    
+    public static final String ONE_PART_MIME_BASE64_LATIN1_BODY = "Hello Mo\u00F6nchengladbach\r\n";
+    
+    public static final String ONE_PART_MIME_QUOTED_PRINTABLE_ASCII_BODY = "Sonnet LXXXI By William Shakespeare\r\n" +
+            "Or I shall live your epitaph to make,\r\n" +
+            "Or you survive when I in earth am rotten;\r\n" +
+            "From hence your memory death cannot take,\r\n" +
+            "Although in me each part will be forgotten.\r\n" +
+            "Your name from hence immortal life shall have,\r\n" +
+            "Though I, once gone, to all the world must die:\r\n" +
+            "The earth can yield me but a common grave,\r\n" +
+            "When you entombed in men's eyes shall lie.\r\n" +
+            "Your monument shall be my gentle verse,\r\n" +
+            "Which eyes not yet created shall o'er-read;\r\n" +
+            "And tongues to be, your being shall rehearse,\r\n" +
+            "When all the breathers of this world are dead;\r\n" +
+            "  You still shall live,--such virtue hath my pen,--\r\n" +
+            "  Where breath most breathes, even in the mouths of men.\r\n"; 
+    
+    private static final byte[] ONE_PART_MIME_BASE64_LATIN1_ENCODED = EncodeUtils.toBase64(latin1(ONE_PART_MIME_BASE64_LATIN1_BODY));
+    
+    public static final String ONE_PART_MIME_BASE64_ASCII_BODY = "Hello, World!\r\n";
+    
+    public static final String ONE_PART_MIME_WITH_CONTENT_DISPOSITION_PARAMETERS =
+        "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+        "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+        "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+        "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+        "Subject: [Mime4J] getReader\r\n" +
+        "MIME-Version: 1.0\r\n" +
+        "Content-Type: text/plain; charset=US-ASCII\r\n" +
+        "Content-Transfer-Encoding: 7bit\r\n" +
+        "Content-Disposition: inline; foo=bar; one=1; param=value;\r\n" +
+        "Content-MD5: " + MD5_CONTENT + "\r\n" +
+        "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+        "\r\n" +
+        ONE_PART_MIME_ASCII_BODY;
+
+    private static final byte[] ONE_PART_MIME_BASE64_ASCII_ENCODED = EncodeUtils.toBase64(ascii(ONE_PART_MIME_BASE64_ASCII_BODY));
+
+    public static final String ONE_PART_MIME_ASCII = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 1.0\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n" +
+    "Content-Transfer-Encoding: 7bit\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n" +
+    ONE_PART_MIME_ASCII_BODY;
+    
+    public static final String ONE_PART_MIME_ASCII_COMMENT_IN_MIME_VERSION = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 2.(This is a comment)4\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n" +
+    "Content-Transfer-Encoding: 7bit\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n" + ONE_PART_MIME_ASCII_BODY;
+    
+    public static final String ONE_PART_MIME_ASCII_MIME_VERSION_SPANS_TWO_LINES = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 4.   \r\n" +
+    "  1\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n" +
+    "Content-Transfer-Encoding: 7bit\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n" + ONE_PART_MIME_ASCII_BODY;
+    
+    public static final String INNER_MAIL = "From: Timothy Tayler <tim@example.org>\r\n" +
+    "To: Joshua Tetley <joshua@example.org>\r\n" +
+    "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+    "Subject: Multipart Without RFC822 Part\r\n" +
+    "Content-Type: multipart/mixed;boundary=42\r\n\r\n" +
+    "--42\r\n" +
+    "Content-Type:text/plain; charset=US-ASCII\r\n\r\n" +
+    "First part of this mail\r\n" +
+    "--42\r\n" +
+    "Content-Type:text/plain; charset=US-ASCII\r\n\r\n" +
+    "Second part of this mail\r\n" +
+    "--42--\r\n";
+
+    public static final String MAIL_WITH_RFC822_PART = "MIME-Version: 1.0\r\n" +
+    "From: Timothy Tayler <tim@example.org>\r\n" +
+    "To: Joshua Tetley <joshua@example.org>\r\n" +
+    "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+    "Subject: Multipart With RFC822 Part\r\n" +
+    "Content-Type: multipart/mixed;boundary=1729\r\n\r\n" +
+    "A short premable\r\n" +
+    "--1729\r\n\r\n" +
+    "First part has no headers\r\n" +
+    "--1729\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+    "Second part is plain text\r\n" +
+    "--1729\r\n" +
+    "Content-Type: message/rfc822\r\n\r\n" +
+    INNER_MAIL +
+    "--1729\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+    "Last part is plain text\r\n" +
+    "--1729--\r\n" +
+    "The End";
+        
+    public static final String ONE_PART_MIME_8859 = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 1.0\r\n" +
+    "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
+    "Content-Transfer-Encoding: 8bit\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Content-ID: " + CONTENT_ID + "\r\n" +
+    "Content-Description: " + CONTENT_DESCRIPTION + "\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n" +
+    ONE_PART_MIME_8859_BODY;
+    
+    public static final String ONE_PART_MIME_BASE64_ASCII_HEADERS = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 1.0\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n" +
+    "Content-Transfer-Encoding: base64\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n";
+    
+    public static final String ONE_PART_MIME_BASE64_LATIN1_HEADERS = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 1.0\r\n" +
+    "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
+    "Content-Transfer-Encoding: base64\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n";
+    
+    public static final String ONE_PART_MIME_QUOTED_PRINTABLE_ASCII = "Received: by 10.114.126.16 with HTTP; Thu, 6 Mar 2008 10:02:03 -0800 (PST)\r\n" +
+    "Message-ID: <f470f68e0803061002n22bc4124he14015a4b6d6327f@mail.gmail.com>\r\n" +
+    "Date: Thu, 6 Mar 2008 18:02:03 +0000\r\n" +
+    "From: \"Robert Burrell Donkin\" <robertburrelldonkin@gmail.com>\r\n" +
+    "To: \"James Developers List\" <server-dev@james.apache.org>\r\n" +
+    "Subject: [Mime4J] getReader\r\n" +
+    "MIME-Version: 1.0\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n" +
+    "Content-Transfer-Encoding: Quoted-Printable\r\n" +
+    "Content-Disposition: inline\r\n" +
+    "Delivered-To: robertburrelldonkin@gmail.com\r\n" +
+    "\r\n" + breakLines(ONE_PART_MIME_QUOTED_PRINTABLE_ASCII_BODY.replaceAll("\r\n", "=0D=0A"));
+    
+    
+    public static final String RFC_SIMPLE = 
+            "From: Timothy Tayler <timothy@example.org>\r\n" +
+            "To: Samual Smith <samual@example.org>\r\n" +
+            "Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)\r\n" +
+            "Subject: A Simple Email\r\n" +
+            "\r\n" +
+            RFC822_SIMPLE_BODY;
+
+    public static final String MIME_RFC822_SIMPLE = 
+        "From: Samual Smith <sam@example.org>\r\n" +
+        "To: Joshua Tetley <josh@example.org>\r\n" +
+        "Date: Thu, 14 Feb 2008 12:30:00 +0000 (GMT)\r\n" +
+        "Subject: FW: A Simple Email\r\n" +
+        "MIME-Version: 1.0\r\n" +
+        "Content-Type: message/rfc822\r\n" +
+        "\r\n" + RFC_SIMPLE;
+    
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_7BIT = "Sonnet XXXIII By William Shakespeare\r\n" +
+            "\r\n" +
+            "Full many a glorious morning have I seen\r\n" +
+            "Flatter the mountain tops with sovereign eye,\r\n" +
+            "Kissing with golden face the meadows green,\r\n" +
+            "Gilding pale streams with heavenly alchemy;\r\n" +
+            "Anon permit the basest clouds to ride\r\n" +
+            "With ugly rack on his celestial face,\r\n" +
+            "And from the forlorn world his visage hide,\r\n" +
+            "Stealing unseen to west with this disgrace:\r\n" +
+            "Even so my sun one early morn did shine,\r\n" +
+            "With all triumphant splendour on my brow;\r\n" +
+            "But out! alack! he was but one hour mine,\r\n" +
+            "The region cloud hath mask'd him from me now.\r\n" +
+            "  Yet him for this my love no whit disdaineth;\r\n" +
+            "  Suns of the world may stain when heaven's sun staineth.\r\n";
+            
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_QUOTED_PRINTABLE = "Sonnet XXXV By William Shakespeare\r\n" +
+            "\r\n" +
+            "No more be griev'd at that which thou hast done:\r\n" +
+            "Roses have thorns, and silver fountains mud:\r\n" +
+            "Clouds and eclipses stain both moon and sun,\r\n" +
+            "And loathsome canker lives in sweetest bud.\r\n" +
+            "All men make faults, and even I in this,\r\n" +
+            "Authorizing thy trespass with compare,\r\n" +
+            "Myself corrupting, salving thy amiss,\r\n" +
+            "Excusing thy sins more than thy sins are;\r\n" +
+            "For to thy sensual fault I bring in sense,--\r\n" +
+            "Thy adverse party is thy advocate,--\r\n" +
+            "And 'gainst myself a lawful plea commence:\r\n" +
+            "Such civil war is in my love and hate,\r\n" +
+            "  That I an accessary needs must be,\r\n" +
+            "  To that sweet thief which sourly robs from me.\r\n"; 
+    
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BASE64 = "Sonnet XXXVIII By William Shakespeare\r\n" +
+            "\r\n" +
+            "How can my muse want subject to invent,\r\n" +
+            "While thou dost breathe, that pour'st into my verse\r\n" +
+            "Thine own sweet argument, too excellent\r\n" +
+            "For every vulgar paper to rehearse?\r\n" +
+            "O! give thy self the thanks, if aught in me\r\n" +
+            "Worthy perusal stand against thy sight;\r\n" +
+            "For who's so dumb that cannot write to thee,\r\n" +
+            "When thou thy self dost give invention light?\r\n" +
+            "Be thou the tenth Muse, ten times more in worth\r\n" +
+            "Than those old nine which rhymers invocate;\r\n" +
+            "And he that calls on thee, let him bring forth\r\n" +
+            "Eternal numbers to outlive long date.\r\n" +
+            "  If my slight muse do please these curious days,\r\n" +
+            "  The pain be mine, but thine shall be the praise.\r\n";
+        
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_ONE = 
+            "From: Timothy Tayler <timothy@example.org>\r\n" +
+            "To: Samual Smith <samual@example.org>\r\n" +
+            "Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)\r\n" +
+            "Subject: A Multipart Email\r\n" +
+            "Content-Type: multipart/mixed;boundary=1729\r\n" +
+            "\r\n" +
+            "Start with a preamble\r\n" +
+            "\r\n" +
+            "--1729\r\n" +
+            "Content-Type: text/plain; charset=US-ASCII\r\n" +
+            "Content-Transfer-Encoding: 7bit\r\n\r\n";
+    
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_TWO = 
+            "\r\n--1729\r\n" +
+            "Content-Type: text/plain; charset=US-ASCII\r\n" +
+            "Content-Transfer-Encoding: Quoted-Printable\r\n\r\n";
+    
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_THREE = 
+            "\r\n--1729\r\n" +
+            "Content-Type: text/plain; charset=US-ASCII\r\n" +
+            "Content-Transfer-Encoding: base64\r\n\r\n";
+            
+    public static final String MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_END = 
+            "\r\n--1729--\r\n";
+    
+    public static final String MIME_MULTIPART_ALTERNATIVE = 
+        "From: Timothy Tayler <timothy@example.org>\r\n" +
+        "To: Samual Smith <samual@example.org>\r\n" +
+        "Date: Thu, 14 Feb 2008 12:00:00 +0000 (GMT)\r\n" +
+        "Subject: A Multipart Email\r\n" +
+        "Content-Type: multipart/alternative;boundary=1729\r\n\r\n" +
+        "Start with a preamble\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: application/xhtml+xml\r\n\r\n" +
+        "<!DOCTYPE html\r\n" +
+        "PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\r\n" +
+        "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n" +
+        "<html><head><title>Rhubarb</title></head><body>Rhubarb!</body></html>\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+        "Rhubarb!\r\n" +
+        "\r\n--1729\r\n" +
+        "Content-Type: text/html; charset=US-ASCII\r\n\r\n" +
+        "<html><head><title>Rhubarb</title></head><body>Rhubarb!</body></html>\r\n" +
+        "\r\n--1729--\r\n" +
+        "This is the epilogue\r\n";
+    
+    
+    private static final byte[][] MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BYTE_ARRAYS = {
+        ascii(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_ONE),
+        ascii(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_7BIT),
+        ascii(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_TWO),
+        ascii(breakLines(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_QUOTED_PRINTABLE.replaceAll("\r\n", "=0D=0A"))),
+        ascii(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_THREE),
+        EncodeUtils.toBase64(ascii(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BASE64)),
+        ascii(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_END),
+    };
+    
+    public static final byte[] MIME_RFC822_SIMPLE_BYTES = ascii(MIME_RFC822_SIMPLE);
+    public static final byte[] MULTIPART_WITH_CONTENT_LOCATION_BYTES = ascii(MULTIPART_WITH_CONTENT_LOCATION);
+    public static final byte[] ONE_PART_MIME_WITH_CONTENT_DISPOSITION_PARAMETERS_BYTES = ascii(ONE_PART_MIME_WITH_CONTENT_DISPOSITION_PARAMETERS);
+    public static final byte[] MIME_MULTIPART_ALTERNATIVE_BYTES = ascii(MIME_MULTIPART_ALTERNATIVE);
+    public static final byte[] MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BYTES = join(MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BYTE_ARRAYS);
+    public static final byte[] ONE_PART_MIME_QUOTED_PRINTABLE_ASCII_BYTES = ascii(ONE_PART_MIME_QUOTED_PRINTABLE_ASCII);
+    public static final byte[] ONE_PART_MIME_BASE64_LATIN1_UPPERCASE_BYTES = join(ascii(ONE_PART_MIME_BASE64_LATIN1_HEADERS.toUpperCase(Locale.UK)), ONE_PART_MIME_BASE64_LATIN1_ENCODED);
+    public static final byte[] ONE_PART_MIME_BASE64_LATIN1_BYTES = join(ascii(ONE_PART_MIME_BASE64_LATIN1_HEADERS), ONE_PART_MIME_BASE64_LATIN1_ENCODED);
+    public static final byte[] ONE_PART_MIME_BASE64_ASCII_BYTES = join(ascii(ONE_PART_MIME_BASE64_ASCII_HEADERS), ONE_PART_MIME_BASE64_ASCII_ENCODED);
+    public static final byte[] RFC822_SIMPLE_BYTES = US_ASCII.encode(RFC_SIMPLE).array();
+    public static final byte[] ONE_PART_MIME_ASCII_BYTES = US_ASCII.encode(ONE_PART_MIME_ASCII).array();
+    public static final byte[] ONE_PART_MIME_8859_BYTES = LATIN1.encode(ONE_PART_MIME_8859).array();
+    public static final byte[] MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES = US_ASCII.encode(MULTIPART_WITH_BINARY_ATTACHMENTS).array();
+    public static final byte[] ONE_PART_MIME_ASCII_COMMENT_IN_MIME_VERSION_BYTES = US_ASCII.encode(ONE_PART_MIME_ASCII_COMMENT_IN_MIME_VERSION).array();
+    public static final byte[] ONE_PART_MIME_ASCII_MIME_VERSION_SPANS_TWO_LINES_BYTES = US_ASCII.encode(ONE_PART_MIME_ASCII_MIME_VERSION_SPANS_TWO_LINES).array();
+    public static final byte[] MAIL_WITH_RFC822_PART_BYTES = ascii(MAIL_WITH_RFC822_PART);
+    public static final byte[] MIME_MULTIPART_EMBEDDED_MESSAGES_BYTES = ascii(MIME_MULTIPART_EMBEDDED_MESSAGES);
+    
+    public static final byte[] ascii(String text) {
+        
+        return US_ASCII.encode(text).array();
+    }
+    
+    public static final byte[] latin1(String text) {
+        
+        return LATIN1.encode(text).array();
+    }
+        
+    public static final byte[] join(byte[] one, byte[] two) {
+        byte[] results = new byte[one.length + two.length];
+        System.arraycopy(one, 0, results, 0, one.length);
+        System.arraycopy(two, 0, results, one.length, two.length);
+        return results;
+    }
+    
+    public static final byte[] join(byte[][] byteArrays) {
+        int length = 0;
+        for (byte[] bytes : byteArrays) {
+            length += bytes.length;
+        }
+        byte[] results = new byte[length];
+        int count = 0;
+        for (byte[] bytes : byteArrays) {
+            System.arraycopy(bytes, 0, results, count, bytes.length);
+            count += bytes.length;
+        }
+        return results;
+    }
+    
+    public static String breakLines(String original) {
+        StringBuilder buffer = new StringBuilder(original);
+        int count = 76;
+        while(count < buffer.length()) {
+            if (buffer.charAt(count) == '=') {
+                count = count - 1;
+            } else if (buffer.charAt(count-1) == '=') {
+                count = count - 4;                
+            } else if (buffer.charAt(count-2) == '=') {
+                count = count - 3;
+            }    
+            buffer.insert(count, '\n');
+            buffer.insert(count, '\r');
+            buffer.insert(count, '=');
+            count += 79;
+        }
+        final String result = buffer.toString();
+        return result;
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/TestUtil.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/TestUtil.java
new file mode 100644
index 0000000..36916b0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/TestUtil.java
@@ -0,0 +1,73 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j;

+

+import java.io.BufferedInputStream;

+import java.io.IOException;

+import java.io.InputStream;

+

+import org.apache.commons.io.IOUtils;

+

+public class TestUtil {

+    public static final String[] TEST_MESSAGES = new String[] {

+            "2002_06_12_doublebound",

+            "ak-0696",

+            "bluedot-postcard",

+            "bluedot-simple",

+            "double-bound-with-embedded",

+            "double-bound",

+            "dup-names",

+            "frag",

+            "german",

+            "hdr-fakeout",

+            "multi-2evil",

+            "multi-2gifs",

+            "multi-clen",

+            "multi-digest",

+            "multi-frag",

+            "multi-igor",

+            "multi-igor2",

+            "multi-nested",

+            "multi-nested2",

+            "multi-nested3",

+            "multi-simple",

+            "multi-weirdspace",

+            "re-fwd",

+            "russian",

+            "simple",

+            "uu-junk-target",

+            "uu-junk",

+            "uu-zeegee"

+    };

+    

+    public static String readResource(String resource, String charset) 

+            throws IOException {

+        

+        return IOUtils.toString(readResourceAsStream(resource), charset);

+    }

+

+    public static InputStream readResourceAsStream(String resource) 

+            throws IOException {

+

+        return new BufferedInputStream(

+                TestUtil.class.getResource(resource).openStream());

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/Base64InputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/Base64InputStreamTest.java
new file mode 100644
index 0000000..42c1f08
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/Base64InputStreamTest.java
@@ -0,0 +1,293 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.ByteArrayInputStream;

+import java.io.ByteArrayOutputStream;

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.UnsupportedEncodingException;

+import java.util.Random;

+

+import org.apache.commons.io.output.NullOutputStream;

+import org.apache.log4j.BasicConfigurator;

+

+import junit.framework.TestCase;

+

+public class Base64InputStreamTest extends TestCase {

+

+    @Override

+    public void setUp() {

+        BasicConfigurator.resetConfiguration();

+        BasicConfigurator.configure();

+    }

+    

+    public void testDecode() throws IOException {

+        ByteArrayInputStream bis = null;

+        Base64InputStream decoder = null;

+        byte[] bytes = null;

+        

+        /*

+         * Simple initial test.

+         */

+        bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlIQ=="));

+        decoder = new Base64InputStream(bis);

+        assertEquals("This is the plain text message!", toString(read(decoder)));

+        

+        /*

+         * Test encoded text padded once, twice and not at all.

+         */

+        bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyBhIHRleHQgd2hpY2ggaGFzIHRvIGJl"

+                        + "IHBhZGRlZCBvbmNlLi4="));

+        decoder = new Base64InputStream(bis);

+        assertEquals("This is a text which has to be padded once..", toString(read(decoder)));

+        bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyBhIHRleHQgd2hpY2ggaGFzIHRvIGJl"

+                        + "IHBhZGRlZCB0d2ljZQ=="));

+        decoder = new Base64InputStream(bis);

+        assertEquals("This is a text which has to be padded twice", toString(read(decoder)));

+        bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyBhIHRleHQgd2hpY2ggd2lsbCBub3Qg"

+                        + "YmUgcGFkZGVk"));

+        decoder = new Base64InputStream(bis);

+        assertEquals("This is a text which will not be padded", toString(read(decoder)));

+        

+        /*

+         * Test that non base64 characters are ignored.

+         */

+        bis = new ByteArrayInputStream(

+                fromString(" &% VGhp\r\ncyBp\r\ncyB0aGUgcGxhaW4g "

+                        + " \tdGV4dCBtZ?!XNzY*WdlIQ=="));

+        decoder = new Base64InputStream(bis);

+        assertEquals("This is the plain text message!", toString(read(decoder)));

+        

+        /*

+         * Test that the bytes 0-255 shifted 0, 1 and 2 positions are

+         * decoded properly.

+         */

+        String s1 = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCU"

+                  + "mJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0"

+                  + "xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bxc"

+                  + "nN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeY"

+                  + "mZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6"

+                  + "/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5O"

+                  + "Xm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==";

+        

+        String s2 = "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSY"

+                  + "nKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE"

+                  + "1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc"

+                  + "3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZ"

+                  + "mpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/"

+                  + "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5e"

+                  + "bn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AA==";

+        

+        String s3 = "AgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJic"

+                  + "oKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU"

+                  + "5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzd"

+                  + "HV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJma"

+                  + "m5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8D"

+                  + "BwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5u"

+                  + "fo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQ==";

+        

+        bis = new ByteArrayInputStream(fromString(s1));

+        decoder = new Base64InputStream(bis);

+        bytes = read(decoder);

+        

+        for (int i = 0; i < bytes.length; i++) {

+            assertEquals("Position " + i, bytes[i], (byte) i);

+        }

+        

+        bis = new ByteArrayInputStream(fromString(s2));

+        decoder = new Base64InputStream(bis);

+        bytes = read(decoder);

+        

+        for (int i = 0; i < bytes.length; i++) {

+            assertEquals("Position " + i, bytes[i], (byte) (i + 1));

+        }

+        

+        bis = new ByteArrayInputStream(fromString(s3));

+        decoder = new Base64InputStream(bis);

+        bytes = read(decoder);

+        

+        for (int i = 0; i < bytes.length; i++) {

+            assertEquals("Position " + i, bytes[i], (byte) (i + 2));

+        }

+    }

+

+    public void testDecodePrematureClose() throws IOException {

+        ByteArrayInputStream bis = null;

+        Base64InputStream decoder = null;

+        

+        bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlIQ=="));

+        decoder = new Base64InputStream(bis);

+        assertEquals('T', decoder.read());

+        assertEquals('h', decoder.read());

+        decoder.close();

+        

+        try {

+            decoder.read();

+            fail();

+        } catch (IOException expected) {

+        }

+    }

+

+    public void testRoundtripWithVariousBufferSizes() throws Exception {

+        byte[] data = new byte[3719];

+        new Random(0).nextBytes(data);

+

+        ByteArrayOutputStream eOut = new ByteArrayOutputStream();

+        CodecUtil.encodeBase64(new ByteArrayInputStream(data), eOut);

+        byte[] encoded = eOut.toByteArray();

+

+        for (int bufferSize = 1; bufferSize <= 1009; bufferSize++) {

+            ByteArrayInputStream bis = new ByteArrayInputStream(encoded);

+            Base64InputStream decoder = new Base64InputStream(bis);

+            ByteArrayOutputStream dOut = new ByteArrayOutputStream();

+

+            final byte[] buffer = new byte[bufferSize];

+            int inputLength;

+            while (-1 != (inputLength = decoder.read(buffer))) {

+                dOut.write(buffer, 0, inputLength);

+            }

+

+            byte[] decoded = dOut.toByteArray();

+

+            assertEquals(data.length, decoded.length);

+            for (int i = 0; i < data.length; i++) {

+                assertEquals(data[i], decoded[i]);

+            }

+        }

+    }

+

+    /**

+     * Tests {@link InputStream#read()}

+     */

+    public void testReadInt() throws Exception {

+        ByteArrayInputStream bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlIQ=="));

+        Base64InputStream decoder = new Base64InputStream(bis);

+        ByteArrayOutputStream out = new ByteArrayOutputStream();

+

+        while (true) {

+            int x = decoder.read();

+            if (x == -1)

+                break;

+            out.write(x);

+        }

+

+        assertEquals("This is the plain text message!", toString(out

+                .toByteArray()));

+    }

+

+    /**

+     * Tests {@link InputStream#read(byte[], int, int)} with various offsets

+     */

+    public void testReadOffset() throws Exception {

+        ByteArrayInputStream bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlIQ=="));

+        Base64InputStream decoder = new Base64InputStream(bis);

+

+        byte[] data = new byte[36];

+        for (int i = 0;;) {

+            int bytes = decoder.read(data, i, 5);

+            if (bytes == -1)

+                break;

+            i += bytes;

+        }

+

+        assertEquals("This is the plain text message!\0\0\0\0\0",

+                toString(data));

+    }

+

+    public void testStrictUnexpectedEof() throws Exception {

+        ByteArrayInputStream bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlI"));

+        Base64InputStream decoder = new Base64InputStream(bis, true);

+        try {

+            CodecUtil.copy(decoder, new NullOutputStream());

+            fail();

+        } catch (IOException expected) {

+            assertTrue(expected.getMessage().toLowerCase().contains(

+                    "end of file"));

+        }

+    }

+

+    public void testLenientUnexpectedEof() throws Exception {

+        ByteArrayInputStream bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlI"));

+        Base64InputStream decoder = new Base64InputStream(bis, false);

+        ByteArrayOutputStream out = new ByteArrayOutputStream();

+        CodecUtil.copy(decoder, out);

+        assertEquals("This is the plain text message", toString(out

+                .toByteArray()));

+    }

+

+    public void testStrictUnexpectedPad() throws Exception {

+        ByteArrayInputStream bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlI="));

+        Base64InputStream decoder = new Base64InputStream(bis, true);

+        try {

+            CodecUtil.copy(decoder, new NullOutputStream());

+            fail();

+        } catch (IOException expected) {

+            assertTrue(expected.getMessage().toLowerCase().contains("pad"));

+        }

+    }

+

+    public void testLenientUnexpectedPad() throws Exception {

+        ByteArrayInputStream bis = new ByteArrayInputStream(

+                fromString("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlI="));

+        Base64InputStream decoder = new Base64InputStream(bis, false);

+        ByteArrayOutputStream out = new ByteArrayOutputStream();

+        CodecUtil.copy(decoder, out);

+        assertEquals("This is the plain text message", toString(out

+                .toByteArray()));

+    }

+        

+    private byte[] read(InputStream is) throws IOException {

+        ByteArrayOutputStream bos = new ByteArrayOutputStream();

+        int b;

+        while ((b = is.read()) != -1) {

+            bos.write(b);

+        }

+        return bos.toByteArray();

+    }

+    

+    private byte[] fromString(String s) {

+        try {

+            return s.getBytes("US-ASCII");

+        } catch (UnsupportedEncodingException e) {

+            fail(e.getMessage());

+            return null;

+        }

+    }

+    

+    private String toString(byte[] b) {

+        try {

+            return new String(b, "US-ASCII");

+        } catch (UnsupportedEncodingException e) {

+            fail(e.getMessage());

+            return null;

+        }

+    }

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/Base64OutputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/Base64OutputStreamTest.java
new file mode 100644
index 0000000..b3870aa
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/Base64OutputStreamTest.java
@@ -0,0 +1,217 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import junit.framework.TestCase;
+
+public class Base64OutputStreamTest extends TestCase {
+
+    public void testEncode() throws IOException {
+        ByteArrayOutputStream bos = null;
+        Base64OutputStream encoder = null;
+        
+        /*
+         * Simple initial test.
+         */
+        bos = new ByteArrayOutputStream();
+        encoder = new Base64OutputStream(bos);
+        encoder.write(fromString("This is the plain text message!"));
+        encoder.close();
+        assertEquals("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlIQ==\r\n", toString(bos.toByteArray()));
+    }
+
+    public void testEncodeUnderlyingStreamStaysOpen() throws IOException {
+        ByteArrayOutputStream bos = null;
+        Base64OutputStream encoder = null;
+        
+        bos = new ByteArrayOutputStream();
+        encoder = new Base64OutputStream(bos);
+        encoder.write(fromString("This is the plain text message!"));
+        encoder.close();
+
+        try {
+            encoder.write('b');
+            fail();
+        } catch (IOException expected) {
+        }
+        
+        bos.write('y');
+        bos.write('a');
+        bos.write('d');
+        bos.write('a');
+        assertEquals("VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCBtZXNzYWdlIQ==\r\nyada", toString(bos.toByteArray()));
+    }
+
+    public void testNoLineSeparators() throws IOException {
+        assertEquals("", encodeNoLs(""));
+        assertEquals("YQ==", encodeNoLs("a"));
+        assertEquals("YWI=", encodeNoLs("ab"));
+        assertEquals("YWJj", encodeNoLs("abc"));
+        assertEquals("YWJjZA==", encodeNoLs("abcd"));
+        assertEquals("YWJjZGU=", encodeNoLs("abcde"));
+        assertEquals("YWJjZGVm", encodeNoLs("abcdef"));
+        assertEquals("YWJjZGVmZw==", encodeNoLs("abcdefg"));
+        assertEquals("YWJjZGVmZ2g=", encodeNoLs("abcdefgh"));
+        assertEquals("YWJjZGVmZ2hp", encodeNoLs("abcdefghi"));
+        assertEquals("DQoMCQ==", encodeNoLs("\r\n\f\t"));
+        assertEquals("LT0/VGhhdCdzIGEgdGVzdD89LQ==",
+                encodeNoLs("-=?That's a test?=-"));
+    }
+
+    public void testLineSeparators() throws IOException {
+        assertEquals("", encodeLs(""));
+        assertEquals("YQ==\r\n", encodeLs("a"));
+        assertEquals("YWJjZA==\r\n", encodeLs("abcd"));
+        assertEquals("YWJjZGVmZw==\r\n", encodeLs("abcdefg"));
+        assertEquals("YWJjZGVmZ2g=\r\n", encodeLs("abcdefgh"));
+        assertEquals("YWJjZGVmZ2hp\r\n", encodeLs("abcdefghi"));
+        assertEquals("YWJjZGVmZ2hp\r\nag==\r\n", encodeLs("abcdefghij"));
+        assertEquals("YWJjZGVmZ2hp\r\nams=\r\n", encodeLs("abcdefghijk"));
+        assertEquals("YWJjZGVmZ2hp\r\namts\r\n", encodeLs("abcdefghijkl"));
+    }
+
+    /**
+     * tests {@link OutputStream#write(int)}
+     */
+    public void testWriteInt() throws IOException {
+        byte[] bytes = fromString("123456789012345678901234567890123456789012"
+                + "3456789012345678901234567890123456789012345678901234567890"
+                + "123456789012345");
+
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        Base64OutputStream out = new Base64OutputStream(b);
+
+        for (byte element : bytes)
+            out.write(element);
+
+        out.close();
+
+        String actual = new String(b.toByteArray(), "US-ASCII");
+
+        String expected = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nz"
+                + "g5MDEyMzQ1Njc4OTAxMjM0NTY3\r\nODkwMTIzNDU2Nzg5MDEyMzQ1Njc4"
+                + "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0\r\nNQ==\r"
+                + "\n";
+
+        assertEquals(expected, actual);
+    }
+
+    /**
+     * tests {@link OutputStream#write(byte[], int, int)} with various offsets
+     */
+    public void testWriteOffset() throws IOException {
+        byte[] bytes = fromString("123456789012345678901234567890123456789012"
+                + "3456789012345678901234567890123456789012345678901234567890"
+                + "123456789012345");
+
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        Base64OutputStream out = new Base64OutputStream(b);
+
+        for (int offset = 0; offset < bytes.length; offset += 2) {
+            int len = Math.min(2, bytes.length - offset);
+            out.write(bytes, offset, len);
+        }
+
+        out.close();
+
+        String actual = new String(b.toByteArray(), "US-ASCII");
+
+        String expected = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nz"
+                + "g5MDEyMzQ1Njc4OTAxMjM0NTY3\r\nODkwMTIzNDU2Nzg5MDEyMzQ1Njc4"
+                + "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0\r\nNQ==\r"
+                + "\n";
+
+        assertEquals(expected, actual);
+    }
+
+    /**
+     * tests {@link OutputStream#flush()} while writing
+     */
+    public void testWriteFlush() throws IOException {
+        byte[] bytes = fromString("123456789012345678901234567890123456789012"
+                + "3456789012345678901234567890123456789012345678901234567890"
+                + "123456789012345");
+
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        Base64OutputStream out = new Base64OutputStream(b);
+
+        for (int offset = 0; offset < bytes.length; offset += 7) {
+            int len = Math.min(7, bytes.length - offset);
+            out.write(bytes, offset, len);
+            out.flush();
+        }
+
+        out.close();
+
+        String actual = new String(b.toByteArray(), "US-ASCII");
+
+        String expected = "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nz"
+                + "g5MDEyMzQ1Njc4OTAxMjM0NTY3\r\nODkwMTIzNDU2Nzg5MDEyMzQ1Njc4"
+                + "OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0\r\nNQ==\r"
+                + "\n";
+
+        assertEquals(expected, actual);
+    }
+
+    private String encodeNoLs(String str) throws IOException {
+        return encode(str, 0, new byte[] {});
+    }
+
+    private String encodeLs(String str) throws IOException {
+        return encode(str, 12, new byte[] { '\r', '\n' });
+    }
+
+    private String encode(String str, int lineLength, byte[] lineSeparator)
+            throws IOException {
+        byte[] bytes = fromString(str);
+
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        Base64OutputStream out = new Base64OutputStream(b, lineLength,
+                lineSeparator);
+
+        out.write(bytes);
+        out.close();
+
+        return toString(b.toByteArray());
+    }
+        
+    private byte[] fromString(String s) {
+        try {
+            return s.getBytes("US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            fail(e.getMessage());
+            return null;
+        }
+    }
+    
+    private String toString(byte[] b) {
+        try {
+            return new String(b, "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            fail(e.getMessage());
+            return null;
+        }
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/CodecUtilTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/CodecUtilTest.java
new file mode 100644
index 0000000..7bd43b5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/CodecUtilTest.java
@@ -0,0 +1,163 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import org.apache.james.mime4j.ExampleMail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class CodecUtilTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testCopy() throws Exception {
+        byte[] content = ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES;
+        ByteArrayInputStream in = new ByteArrayInputStream(content);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.copy(in, out);
+        assertEquals(content, out.toByteArray());
+    }
+    
+    public void testEncodeQuotedPrintableLargeInput() throws Exception {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 1024 * 5; i++) {
+            sb.append((char) ('0' + (i % 10)));
+        }
+        String expected = sb.toString().replaceAll("(\\d{75})", "$1=\r\n");
+        
+        InputStream in = new ByteArrayInputStream(sb.toString().getBytes("US-ASCII"));
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeQuotedPrintableBinary(in, out);
+        String actual = new String(out.toByteArray(), "US-ASCII");
+        assertEquals(expected, actual);
+    }
+
+    public void testEncodeQuotedPrintableNonAsciiChars() throws Exception {
+        String s = "7bit content with euro \u20AC symbol";
+        InputStream in = new ByteArrayInputStream(s.getBytes("iso-8859-15"));
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeQuotedPrintableBinary(in, out);
+        String actual = new String(out.toByteArray(), "US-ASCII");
+        assertEquals("7bit=20content=20with=20euro=20=A4=20symbol", actual);
+    }
+    
+    public void testBase64OutputStream() throws Exception {
+        StringBuilder sb = new StringBuilder(2048);
+        for (int i = 0; i < 128; i++) {
+            sb.append("0123456789ABCDEF");
+        }
+        String input = sb.toString();
+        String output = roundtripUsingOutputStream(input);
+        assertEquals(input, output);
+    }
+
+    private String roundtripUsingOutputStream(String input) throws IOException {
+        ByteArrayOutputStream out2 = new ByteArrayOutputStream();
+        Base64OutputStream outb64 = new Base64OutputStream(out2, 76);
+        CodecUtil.copy(new ByteArrayInputStream(input.getBytes()), outb64);
+        outb64.flush();
+        outb64.close();
+        
+        InputStream is = new Base64InputStream(new ByteArrayInputStream(out2.toByteArray()));
+        ByteArrayOutputStream outRoundtrip = new ByteArrayOutputStream();
+        CodecUtil.copy(is, outRoundtrip);
+        String output = new String(outRoundtrip.toByteArray());
+        return output;
+    }
+    
+    /**
+     * This test is a proof for MIME4J-67
+     */
+    public void testBase64Encoder() throws Exception {
+        StringBuilder sb = new StringBuilder(2048);
+        for (int i = 0; i < 128; i++) {
+            sb.append("0123456789ABCDEF");
+        }
+        String input = sb.toString();
+        String output = roundtripUsingEncoder(input);
+        assertEquals(input, output);
+    }
+
+    private String roundtripUsingEncoder(String input) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeBase64(new ByteArrayInputStream(input.getBytes()), out);
+        
+        InputStream is = new Base64InputStream(new ByteArrayInputStream(out.toByteArray()));
+        ByteArrayOutputStream outRoundtrip = new ByteArrayOutputStream();
+        CodecUtil.copy(is, outRoundtrip);
+        String output = new String(outRoundtrip.toByteArray());
+        return output;
+    } 
+    
+    /* performance test, not a unit test */
+    /*
+    public void testPerformance() throws Exception {
+        // if (true) return;
+        byte[] bytes = new byte[10000];
+        Random r = new Random(432875623874L);
+        r.nextBytes(bytes);
+        long totalEncoder1 = 0;
+        long totalStream1 = 0;
+        long totalEncoder2 = 0;
+        for (int i = 0; i < 10000; i++) {
+            int length = r.nextInt(1000);
+            int pos = r.nextInt(9000);
+            String input = new String(bytes, pos, length);
+            long time1 = System.currentTimeMillis();
+            roundtripUsingEncoder(input);
+            long time2 = System.currentTimeMillis();
+            roundtripUsingOutputStream(input);
+            long time3 = System.currentTimeMillis();
+            roundtripUsingEncoder(input);
+            long time4 = System.currentTimeMillis();
+            
+            totalEncoder1 += time2-time1;
+            totalStream1 += time3-time2;
+            totalEncoder2 += time4-time3;
+        }
+        
+        System.out.println("Encoder 1st: "+totalEncoder1);
+        System.out.println("Encoder 2nd: "+totalEncoder2);
+        System.out.println("Stream 1st: "+totalStream1);
+    }
+    */
+    
+    private void assertEquals(byte[] expected, byte[] actual) {
+        StringBuilder buffer = new StringBuilder(expected.length);
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < actual.length; i++) {
+            buffer.append((char)actual[i]);
+            assertEquals("Mismatch@" + i, expected[i], actual[i]);
+        }
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java
new file mode 100644
index 0000000..d334045
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/DecoderUtilTest.java
@@ -0,0 +1,105 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.UnsupportedEncodingException;

+

+import junit.framework.TestCase;

+

+import org.apache.log4j.BasicConfigurator;

+

+public class DecoderUtilTest extends TestCase {

+

+    @Override

+    public void setUp() {

+        BasicConfigurator.resetConfiguration();

+        BasicConfigurator.configure();

+    }

+    /*

+    public void testDecodeEncodedWords() {

+        String s = "=?ISO-2022-JP?B?GyRCTCQbKEobJEI+NRsoShskQkJ6GyhKGyRCOS0bKEo=?= "

+                 + "=?ISO-2022-JP?B?GyRCOXAbKEobJEIiKBsoShskQiU1GyhKGyRCJSQbKEo=?= "

+                 + "=?ISO-2022-JP?B?GyRCJUkbKEobJEIlUxsoShskQiU4GyhKGyRCJU0bKEo=?= "  

+                 + "=?ISO-2022-JP?B?GyRCJTkbKEobJEIkThsoShskQjdoGyhKGyRCRGobKEo=?= "

+                 + "=?ISO-2022-JP?B?GyRCSEcbKEobJEIkRxsoShskQiQ5GyhKGyRCISobKEo=?=";      

+        

+        s = DecoderUtil.decodeEncodedWords(s);

+        System.out.println(s);

+    }*/

+    

+    public void testDecodeB() throws UnsupportedEncodingException {

+        String s = DecoderUtil.decodeB("VGhpcyBpcyB0aGUgcGxhaW4gd"

+                    + "GV4dCBtZXNzYWdlIQ==", "ISO8859-1");

+        assertEquals("This is the plain text message!", s);

+    }

+    

+

+    public void testDecodeQ() throws UnsupportedEncodingException {

+        String s = DecoderUtil.decodeQ("=e1_=e2=09=E3_=E4_", 

+                                                         "ISO8859-1");

+        assertEquals("\u00e1 \u00e2\t\u00e3 \u00e4 ", s);

+    }

+    

+    public void testDecodeEncodedWords() {

+        assertEquals("", DecoderUtil.decodeEncodedWords(""));

+        assertEquals("Yada yada", DecoderUtil.decodeEncodedWords("Yada yada"));

+        assertEquals("  \u00e1\u00e2\u00e3\t\u00e4", 

+                DecoderUtil.decodeEncodedWords("=?iso-8859-1?Q?_=20=e1=e2=E3=09=E4?="));

+        assertEquals("Word 1 '  \u00e2\u00e3\t\u00e4'. Word 2 '  \u00e2\u00e3\t\u00e4'", 

+                DecoderUtil.decodeEncodedWords("Word 1 '=?iso-8859-1?Q?_=20=e2=E3=09=E4?="

+                        + "'. Word 2 '=?iso-8859-1?q?_=20=e2=E3=09=E4?='"));

+        assertEquals("=?iso-8859-YADA?Q?_=20=t1=e2=E3=09=E4?=", 

+                DecoderUtil.decodeEncodedWords("=?iso-8859-YADA?Q?_=20=t1=e2=E3=09=E4?="));

+        assertEquals("A short text", 

+                DecoderUtil.decodeEncodedWords("=?US-ASCII?B?QSBzaG9ydCB0ZXh0?="));

+        assertEquals("A short text again!", 

+                DecoderUtil.decodeEncodedWords("=?US-ASCII?b?QSBzaG9ydCB0ZXh0IGFnYWluIQ==?="));

+

+        // invalid encoded words should be returned unchanged

+        assertEquals("=?iso8859-1?Q?=", DecoderUtil.decodeEncodedWords("=?iso8859-1?Q?="));

+        assertEquals("=?iso8859-1?b?=", DecoderUtil.decodeEncodedWords("=?iso8859-1?b?="));

+        assertEquals("=?ISO-8859-1?Q?", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?"));

+        assertEquals("=?ISO-8859-1?R?abc?=", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?R?abc?="));

+

+        // encoded-text requires at least one character according to rfc 2047

+        assertEquals("=?ISO-8859-1?Q??=", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q??="));

+        assertEquals("=?ISO-8859-1?B??=", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?B??="));

+        

+        // white space between encoded words should be removed (MIME4J-104)

+        assertEquals("a", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?="));

+        assertEquals("a b", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?= b"));

+        assertEquals("ab", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="));

+        assertEquals("ab", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?=  =?ISO-8859-1?Q?b?="));

+        assertEquals("ab", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?=\r\n  =?ISO-8859-1?Q?b?="));

+        assertEquals("a b", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a_b?="));

+        assertEquals("a b", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?="));

+

+        // non white space between encoded words should be retained

+        assertEquals("a b c", DecoderUtil.decodeEncodedWords("=?ISO-8859-1?Q?a?= b =?ISO-8859-1?Q?c?="));

+

+        // text before and after encoded words should be retained

+        assertEquals(" a b c ", DecoderUtil.decodeEncodedWords(" =?ISO-8859-1?Q?a?= b =?ISO-8859-1?Q?c?= "));

+        assertEquals("! a b c !", DecoderUtil.decodeEncodedWords("! =?ISO-8859-1?Q?a?= b =?ISO-8859-1?Q?c?= !"));

+        

+        // Bug detected on June 7, 2005. Decoding the following string caused

+        // OutOfMemoryError.

+        assertEquals("=3?!!\\=?\"!g6P\"!Xp:\"!", DecoderUtil.decodeEncodedWords("=3?!!\\=?\"!g6P\"!Xp:\"!"));

+    }    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/EncoderUtilTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/EncoderUtilTest.java
new file mode 100644
index 0000000..d41e74a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/EncoderUtilTest.java
@@ -0,0 +1,202 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.codec.EncoderUtil.Encoding;
+import org.apache.james.mime4j.codec.EncoderUtil.Usage;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class EncoderUtilTest extends TestCase {
+
+    public void testEncodeAddressDisplayName() throws Exception {
+        assertEquals("\"\"", EncoderUtil.encodeAddressDisplayName(""));
+        assertEquals("test", EncoderUtil.encodeAddressDisplayName("test"));
+        assertEquals(" test ", EncoderUtil.encodeAddressDisplayName(" test "));
+        assertEquals(" test\ttest ", EncoderUtil
+                .encodeAddressDisplayName(" test\ttest "));
+        assertEquals("\"test()\"", EncoderUtil
+                .encodeAddressDisplayName("test()"));
+        assertEquals("\"John Q. Public\"", EncoderUtil
+                .encodeAddressDisplayName("John Q. Public"));
+        assertEquals("\"Giant; \\\"Big\\\" Box\"", EncoderUtil
+                .encodeAddressDisplayName("Giant; \"Big\" Box"));
+        assertEquals("=?ISO-8859-1?Q?Semmelbr=F6sel?=", EncoderUtil
+                .encodeAddressDisplayName("Semmelbr\366sel"));
+        // dollar sign as to be encoded as =24 when used as a word in a phrase
+        assertEquals("=?UTF-8?Q?Dollar_=24_Euro_=E2=82=AC?=", EncoderUtil
+                .encodeAddressDisplayName("Dollar $ Euro \u20ac"));
+    }
+
+    public void testEncodeAddressLocalPart() throws Exception {
+        assertEquals("john.wayne", EncoderUtil
+                .encodeAddressLocalPart("john.wayne"));
+        assertEquals("\"clint eastwood\"", EncoderUtil
+                .encodeAddressLocalPart("clint eastwood"));
+    }
+
+    public void testEncodeHeaderParameter() throws Exception {
+        assertEquals("p=test", EncoderUtil.encodeHeaderParameter("p", "test"));
+        assertEquals("p=\"test test\"", EncoderUtil.encodeHeaderParameter("p",
+                "test test"));
+        assertEquals("p=\"=test\"", EncoderUtil.encodeHeaderParameter("p",
+                "=test"));
+        assertEquals("p=\"\\\\test\"", EncoderUtil.encodeHeaderParameter("p",
+                "\\test"));
+        assertEquals("p=\"\\\"\\\\\\\"\"", EncoderUtil.encodeHeaderParameter(
+                "p", "\"\\\""));
+    }
+
+    public void testHasToBeEncoded() throws Exception {
+        assertFalse(EncoderUtil.hasToBeEncoded("", 0));
+        assertFalse(EncoderUtil.hasToBeEncoded("only ascii characters", 0));
+
+        assertTrue(EncoderUtil.hasToBeEncoded("non-printable ascii: \010", 0));
+        assertTrue(EncoderUtil.hasToBeEncoded("non-ascii: \u20ac", 0));
+
+        assertFalse(EncoderUtil.hasToBeEncoded("123456789012345678901234567",
+                50));
+        assertTrue(EncoderUtil.hasToBeEncoded("1234567890123456789012345678",
+                50));
+        assertFalse(EncoderUtil.hasToBeEncoded(
+                "\t12345678901234567890123456789", 50));
+    }
+
+    public void testEncodeEncodedWordDetectCharset() throws Exception {
+        assertTrue(EncoderUtil
+                .encodeEncodedWord("only ascii", Usage.TEXT_TOKEN).startsWith(
+                        "=?US-ASCII?"));
+        assertTrue(EncoderUtil.encodeEncodedWord("latin 1: \344",
+                Usage.TEXT_TOKEN).startsWith("=?ISO-8859-1?"));
+        assertTrue(EncoderUtil.encodeEncodedWord("unicode: \u20ac",
+                Usage.TEXT_TOKEN).startsWith("=?UTF-8?"));
+    }
+
+    public void testEncodeEncodedWordForceCharset() throws Exception {
+        assertTrue(EncoderUtil.encodeEncodedWord("only ascii",
+                Usage.TEXT_TOKEN, 0, CharsetUtil.UTF_8, null).startsWith(
+                "=?UTF-8?"));
+    }
+
+    public void testEncodeEncodedWordDetectEncoding() throws Exception {
+        assertTrue(EncoderUtil
+                .encodeEncodedWord("only ascii", Usage.TEXT_TOKEN).startsWith(
+                        "=?US-ASCII?Q?"));
+        assertTrue(EncoderUtil.encodeEncodedWord("\344\344\344\344\344",
+                Usage.TEXT_TOKEN).startsWith("=?ISO-8859-1?B?"));
+    }
+
+    public void testEncodeEncodedWordForceEncoding() throws Exception {
+        assertTrue(EncoderUtil.encodeEncodedWord("only ascii",
+                Usage.TEXT_TOKEN, 0, null, Encoding.B).startsWith(
+                "=?US-ASCII?B?"));
+    }
+
+    public void testEncodeEncodedWordSplit() throws Exception {
+        String sixty = "123456789012345678901234567890123456789012345678901234567890";
+
+        String expected = "=?US-ASCII?Q?" + sixty + "?=";
+        assertEquals(expected, EncoderUtil.encodeEncodedWord(sixty,
+                Usage.TEXT_TOKEN, 0, null, Encoding.Q));
+        assertEquals(75, expected.length());
+
+        String sixtyOne = sixty + "1";
+        String encodedSixtyOne = EncoderUtil.encodeEncodedWord(sixtyOne,
+                Usage.TEXT_TOKEN, 0, null, Encoding.Q);
+        assertTrue(encodedSixtyOne.contains("?= =?US-ASCII?Q?"));
+    }
+
+    public void testEncodeEncodedWord() throws Exception {
+        assertEquals("=?US-ASCII?Q??=", EncoderUtil.encodeEncodedWord("",
+                Usage.TEXT_TOKEN, 0, null, Encoding.Q));
+
+        assertEquals("=?US-ASCII?Q?testing_123?=", EncoderUtil
+                .encodeEncodedWord("testing 123", Usage.TEXT_TOKEN, 0, null,
+                        Encoding.Q));
+
+        assertEquals("=?US-ASCII?B?dGVzdGluZyAxMjM=?=", EncoderUtil
+                .encodeEncodedWord("testing 123", Usage.TEXT_TOKEN, 0, null,
+                        Encoding.B));
+
+        assertEquals("=?windows-1252?Q?100_=80?=", EncoderUtil
+                .encodeEncodedWord("100 \u20ac", Usage.TEXT_TOKEN, 0, Charset
+                        .forName("Cp1252"), Encoding.Q));
+
+        assertEquals("=?windows-1252?B?MTAwIIA=?=", EncoderUtil
+                .encodeEncodedWord("100 \u20ac", Usage.TEXT_TOKEN, 0, Charset
+                        .forName("Cp1252"), Encoding.B));
+    }
+
+    public void testEncodeB() throws Exception {
+        assertEquals("", encodeB(""));
+        assertEquals("YQ==", encodeB("a"));
+        assertEquals("YWI=", encodeB("ab"));
+        assertEquals("YWJj", encodeB("abc"));
+        assertEquals("YWJjZA==", encodeB("abcd"));
+        assertEquals("YWJjZGU=", encodeB("abcde"));
+        assertEquals("YWJjZGVm", encodeB("abcdef"));
+        assertEquals("YWJjZGVmZw==", encodeB("abcdefg"));
+        assertEquals("YWJjZGVmZ2g=", encodeB("abcdefgh"));
+        assertEquals("YWJjZGVmZ2hp", encodeB("abcdefghi"));
+        assertEquals("DQoMCQ==", encodeB("\r\n\f\t"));
+        assertEquals("LT0/VGhhdCdzIGEgdGVzdD89LQ==",
+                encodeB("-=?That's a test?=-"));
+    }
+
+    public void testEncodeQRegular() throws Exception {
+        byte[] b = new byte[132];
+        for (int i = 0; i < 132; i++) {
+            b[i] = (byte) i;
+        }
+
+        String expected = "=00=01=02=03=04=05=06=07=08=09=0A=0B=0C=0D=0E=0F"
+                + "=10=11=12=13=14=15=16=17=18=19=1A=1B=1C=1D=1E=1F_!\"#$%&"
+                + "'()*+,-./0123456789:;<=3D>=3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                + "[\\]^=5F`abcdefghijklmnopqrstuvwxyz{|}~=7F=80=81=82=83";
+        assertEquals(expected, EncoderUtil.encodeQ(b, Usage.TEXT_TOKEN));
+    }
+
+    public void testEncodeQRestricted() throws Exception {
+        byte[] b = new byte[136];
+        for (int i = 0; i < 136; i++) {
+            b[i] = (byte) i;
+        }
+
+        String expected = "=00=01=02=03=04=05=06=07=08=09=0A=0B=0C=0D=0E=0F"
+                + "=10=11=12=13=14=15=16=17=18=19=1A=1B=1C=1D=1E=1F_!=22=23"
+                + "=24=25=26=27=28=29*+=2C-=2E/0123456789=3A=3B=3C=3D=3E=3F"
+                + "=40ABCDEFGHIJKLMNOPQRSTUVWXYZ=5B=5C=5D=5E=5F=60abcdefghi"
+                + "jklmnopqrstuvwxyz=7B=7C=7D=7E=7F=80=81=82=83=84=85=86=87";
+        assertEquals(expected, EncoderUtil.encodeQ(b, Usage.WORD_ENTITY));
+    }
+
+    private String encodeB(String s) {
+        try {
+            return EncoderUtil.encodeB(s.getBytes("us-ascii"));
+        } catch (UnsupportedEncodingException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableEncodeTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableEncodeTest.java
new file mode 100644
index 0000000..3c1243f
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableEncodeTest.java
@@ -0,0 +1,141 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class QuotedPrintableEncodeTest extends TestCase {
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testEscapedSoftBreak() throws Exception {
+        byte[] content = new byte[500];
+        Arrays.fill(content, (byte)0x20);
+        byte[] expected = new byte[1557];
+        int index = 0;
+        for (int l=0;l<20;l++) {
+            for (int i=0;i<25;i++) {
+                expected[index++] = '=';
+                expected[index++] = '2';
+                expected[index++] = '0';
+            }
+            if (l<19) {
+                expected[index++] = '=';
+                expected[index++] = '\r';
+                expected[index++] = '\n';
+            }
+        }
+        check(content, expected);
+    }
+    
+    public void testPlainAsciiSoftBreak() throws Exception {
+        byte[] content = new byte[500];
+        Arrays.fill(content, (byte)0x29);
+        byte[] expected = new byte[518];
+        Arrays.fill(expected, (byte)0x29);
+        expected[75] = '=';
+        expected[76] = '\r';
+        expected[77] = '\n';
+        expected[153] = '=';
+        expected[154] = '\r';
+        expected[155] = '\n';
+        expected[231] = '=';
+        expected[232] = '\r';
+        expected[233] = '\n';
+        expected[309] = '=';
+        expected[310] = '\r';
+        expected[311] = '\n';
+        expected[387] = '=';
+        expected[388] = '\r';
+        expected[389] = '\n';
+        expected[465] = '=';
+        expected[466] = '\r';
+        expected[467] = '\n';
+        check(content, expected);
+    }
+    
+    public void testPlainASCII() throws Exception {
+        checkRoundtrip("Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage." +
+                "Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage." +
+                "Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage." +
+                "Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage.");
+    }
+    
+    public void testEncodeSpace() throws Exception {
+        checkRoundtrip("                 ");
+    }
+    
+    public void testLetterEncoding() throws Exception {
+        for (byte b=0;b<Byte.MAX_VALUE;b++) {
+            byte[] content = {b};
+            checkRoundtrip(content);
+        }
+    }
+    
+    private void checkRoundtrip(String content) throws Exception {
+        checkRoundtrip(content, CharsetUtil.US_ASCII);
+    }
+
+    private void checkRoundtrip(String content, Charset charset) throws Exception {
+        checkRoundtrip(charset.encode(content).array());
+    }
+    
+    private void checkRoundtrip(byte[] content) throws Exception {
+        InputStream in = new ByteArrayInputStream(content);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeQuotedPrintableBinary(in, out);
+        // read back through decoder
+        in = new QuotedPrintableInputStream(new ByteArrayInputStream(out.toByteArray()));
+        out = new ByteArrayOutputStream();
+        IOUtils.copy(in, out);
+        assertEquals(content, out.toByteArray());
+    }
+    
+    private void check(byte[] content, byte[] expected) throws Exception {
+        ByteArrayInputStream in = new ByteArrayInputStream(content);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeQuotedPrintableBinary(in, out);
+        assertEquals(expected, out.toByteArray());
+    }
+    
+    private void assertEquals(byte[] expected, byte[] actual) {
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < actual.length; i++) {
+            assertEquals("Mismatch@" + i, expected[i], actual[i]);
+        }
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java
new file mode 100644
index 0000000..bc98574
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableInputStreamTest.java
@@ -0,0 +1,97 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.codec;

+

+import java.io.ByteArrayInputStream;

+import java.io.ByteArrayOutputStream;

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.UnsupportedEncodingException;

+

+import junit.framework.TestCase;

+

+import org.apache.log4j.BasicConfigurator;

+

+public class QuotedPrintableInputStreamTest extends TestCase {

+

+    @Override

+    public void setUp() {

+        BasicConfigurator.resetConfiguration();

+        BasicConfigurator.configure();

+    }

+    

+    public void testDecode() throws IOException, UnsupportedEncodingException {

+        ByteArrayInputStream bis = null;

+        QuotedPrintableInputStream decoder = null;

+

+        bis = new ByteArrayInputStream("=e1=e2=E3=E4\r\n".getBytes("US-ASCII"));

+        decoder = new QuotedPrintableInputStream(bis);

+        assertEquals("\u00e1\u00e2\u00e3\u00e4\r\n", new String(read(decoder), "ISO8859-1"));

+        

+        bis = new ByteArrayInputStream("=e1=g2=E3=E4\r\n".getBytes("US-ASCII"));

+        decoder = new QuotedPrintableInputStream(bis);

+        assertEquals("\u00e1=g2\u00e3\u00e4\r\n", new String(read(decoder), "ISO8859-1"));

+        

+        bis = new ByteArrayInputStream("   =e1 =e2  =E3\t=E4  \t \t    \r\n".getBytes("US-ASCII"));

+        decoder = new QuotedPrintableInputStream(bis);

+        assertEquals("   \u00e1 \u00e2  \u00e3\t\u00e4\r\n", new String(read(decoder), "ISO8859-1"));

+        

+        /*

+         * Test soft line breaks.

+         */

+        bis = new ByteArrayInputStream("Soft line   = \t \r\nHard line   \r\n".getBytes("US-ASCII"));

+        decoder = new QuotedPrintableInputStream(bis);

+        assertEquals("Soft line   Hard line\r\n", new String(read(decoder), "ISO8859-1"));

+        

+        /*

+         * This isn't valid qp (==) but it is known to occur in certain

+         * messages, especially spam.

+         */

+        bis = new ByteArrayInputStream("width==\r\n340 height=3d200\r\n".getBytes("US-ASCII"));

+        decoder = new QuotedPrintableInputStream(bis);

+        assertEquals("width=340 height=200\r\n", new String(read(decoder), "ISO8859-1"));

+    }

+

+    public void testDecodePrematureClose() throws IOException, UnsupportedEncodingException {

+        ByteArrayInputStream bis = null;

+        QuotedPrintableInputStream decoder = null;

+

+        bis = new ByteArrayInputStream("=e1=e2=E3=E4\r\n".getBytes("US-ASCII"));

+        decoder = new QuotedPrintableInputStream(bis);

+        assertEquals('\u00e1', decoder.read());

+        assertEquals('\u00e2', decoder.read());

+        decoder.close();

+        

+        try {

+            decoder.read();

+            fail();

+        } catch (IOException expected) {

+        }

+    }

+    

+    private byte[] read(InputStream is) throws IOException {

+        ByteArrayOutputStream bos = new ByteArrayOutputStream();

+        int b;

+        while ((b = is.read()) != -1) {

+            bos.write(b);

+        }

+        return bos.toByteArray();

+    }

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStreamTest.java
new file mode 100644
index 0000000..3f863f8
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableOutputStreamTest.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import junit.framework.TestCase;
+
+public class QuotedPrintableOutputStreamTest extends TestCase {
+
+    public void testEncode() throws IOException {
+        ByteArrayOutputStream bos = null;
+        QuotedPrintableOutputStream encoder = null;
+        
+        /*
+         * Simple initial test.
+         */
+        bos = new ByteArrayOutputStream();
+        encoder = new QuotedPrintableOutputStream(bos, false);
+        encoder.write(fromString("This is the plain text message containing a few euros: 100 \u20ac!"));
+        encoder.close();
+        assertEquals("This is the plain text message containing a few euros: 100 =E2=82=AC!",
+                toString(bos.toByteArray()));
+    }
+
+    public void testEncodeUnderlyingStreamStaysOpen() throws IOException {
+        ByteArrayOutputStream bos = null;
+        QuotedPrintableOutputStream encoder = null;
+        
+        bos = new ByteArrayOutputStream();
+        encoder = new QuotedPrintableOutputStream(bos, false);
+        encoder.write(fromString("This is the plain text message containing a few euros: 100 \u20ac!"));
+        encoder.close();
+
+        try {
+            encoder.write('b');
+            fail();
+        } catch (IOException expected) {
+        }
+        
+        bos.write('y');
+        bos.write('a');
+        bos.write('d');
+        bos.write('a');
+        assertEquals("This is the plain text message containing a few euros: 100 =E2=82=AC!yada",
+                toString(bos.toByteArray()));
+    }
+
+    private byte[] fromString(String s) {
+        try {
+            return s.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            fail(e.getMessage());
+            return null;
+        }
+    }
+
+    private String toString(byte[] b) {
+        try {
+            return new String(b, "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            fail(e.getMessage());
+            return null;
+        }
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java
new file mode 100644
index 0000000..3c5d891
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/codec/QuotedPrintableTextEncodeTest.java
@@ -0,0 +1,183 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.codec;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class QuotedPrintableTextEncodeTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testEscapedSoftBreak() throws Exception {
+        byte[] content = new byte[500];
+        Arrays.fill(content, (byte)0x18);
+        byte[] expected = new byte[1557];
+        int index = 0;
+        for (int l=0;l<20;l++) {
+            for (int i=0;i<25;i++) {
+                expected[index++] = '=';
+                expected[index++] = '1';
+                expected[index++] = '8';
+            }
+            if (l<19) {
+                expected[index++] = '=';
+                expected[index++] = '\r';
+                expected[index++] = '\n';
+            }
+        }
+        check(content, expected);
+    }
+    
+    public void testPlainAsciiSoftBreak() throws Exception {
+        byte[] content = new byte[500];
+        Arrays.fill(content, (byte)0x29);
+        byte[] expected = new byte[518];
+        Arrays.fill(expected, (byte)0x29);
+        expected[75] = '=';
+        expected[76] = '\r';
+        expected[77] = '\n';
+        expected[153] = '=';
+        expected[154] = '\r';
+        expected[155] = '\n';
+        expected[231] = '=';
+        expected[232] = '\r';
+        expected[233] = '\n';
+        expected[309] = '=';
+        expected[310] = '\r';
+        expected[311] = '\n';
+        expected[387] = '=';
+        expected[388] = '\r';
+        expected[389] = '\n';
+        expected[465] = '=';
+        expected[466] = '\r';
+        expected[467] = '\n';
+        check(content, expected);
+    }
+    
+    public void testPlainASCII() throws Exception {
+        checkRoundtrip("Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage." +
+                "Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage." +
+                "Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage." +
+                "Thisisaverysimplemessage.Thisisaverysimplemessage.Thisisaverysimplemessage.");
+    }
+    
+    public void testEncodeSpace() throws Exception {
+        checkRoundtrip("                 A");
+    }
+    
+    public void testLetterEncoding() throws Exception {
+        for (byte b=0;b<Byte.MAX_VALUE;b++) {
+            byte[] content = {b};
+            // White space is only escaped when followed by CRLF
+            if (b != 32 && b != 9) { 
+                checkRoundtrip(content);
+            }
+        }
+    }
+    
+    public void testCRLFShouldResetLineCount() throws Exception {
+        StringBuilder buffer = new StringBuilder(4096);
+        for (int i=0;i<1000;i++) {
+            buffer.append("Hugo\r\n");
+        }
+        String longLine = buffer.toString();
+        check(longLine, longLine);
+    }
+    
+    public void testDontEscapeLF() throws Exception {
+        check("Ready\nFor\n", "Ready\nFor\n");
+    }
+    
+    public void testDontEscapeCR() throws Exception {
+        check("Ready\rFor\r", "Ready\rFor\r");
+    }
+    
+    public void testEscapeSpaceAtLineEnd() throws Exception {
+        check("      \r\n", "     =20\r\n");
+    }
+    
+    public void testDontEscapeSpaceBeforeLineEnd() throws Exception {
+        check("      ", "      ");
+    }
+    
+    public void testDontEscapeTabsBeforeLineEnd() throws Exception {
+        check("\t\t\t\t", "\t\t\t\t");
+    }
+    
+    public void testDontWhiteSpaceBeforeLineEnd() throws Exception {
+        check("  \t\t  \t", "  \t\t  \t");
+    }
+    
+    private void checkRoundtrip(String content) throws Exception {
+        checkRoundtrip(content, CharsetUtil.US_ASCII);
+    }
+
+    private void checkRoundtrip(String content, Charset charset) throws Exception {
+        checkRoundtrip(charset.encode(content).array());
+    }
+    
+    private void checkRoundtrip(byte[] content) throws Exception {
+        InputStream in = new ByteArrayInputStream(content);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeQuotedPrintable(in, out);
+        // read back through decoder
+        in = new QuotedPrintableInputStream(new ByteArrayInputStream(out.toByteArray()));
+        out = new ByteArrayOutputStream();
+        IOUtils.copy(in, out);
+        assertEquals(content, out.toByteArray());
+    }
+    
+    private void check(String content, String expected) throws Exception {
+        Charset ascii = CharsetUtil.US_ASCII;
+        check(ascii.encode(content).array(), ascii.encode(expected).array());
+    }
+
+    
+    private void check(byte[] content, byte[] expected) throws Exception {
+        ByteArrayInputStream in = new ByteArrayInputStream(content);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        CodecUtil.encodeQuotedPrintable(in, out);
+        assertEquals(expected, out.toByteArray());
+    }
+    
+    private void assertEquals(byte[] expected, byte[] actual) {
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < actual.length; i++) {
+            assertEquals("Mismatch@" + i, expected[i], actual[i]);
+        }
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java
new file mode 100644
index 0000000..afd73ce
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/BaseTestForBodyDescriptors.java
@@ -0,0 +1,237 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.descriptor;

+

+import junit.framework.TestCase;

+

+import org.apache.james.mime4j.parser.Field;

+import org.apache.james.mime4j.util.ByteSequence;

+

+public abstract class BaseTestForBodyDescriptors extends TestCase {

+

+    protected abstract MutableBodyDescriptor newBodyDescriptor();

+

+    protected abstract MutableBodyDescriptor newBodyDescriptor(BodyDescriptor parent);

+    

+    public void testGetParameters() {

+        MutableBodyDescriptor bd = null;

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/plain; charset=ISO-8859-1; "

+                + "boundary=foo; param1=value1; param2=value2; param3=value3"));

+        assertEquals(3, bd.getContentTypeParameters().size());

+        assertEquals("value1", bd.getContentTypeParameters().get("param1"));

+        assertEquals("value2", bd.getContentTypeParameters().get("param2"));

+        assertEquals("value3", bd.getContentTypeParameters().get("param3"));

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/plain; param1=value1; param2=value2;"

+                     + " param3=value3"));

+        assertEquals(3, bd.getContentTypeParameters().size());

+        assertEquals("value1", bd.getContentTypeParameters().get("param1"));

+        assertEquals("value2", bd.getContentTypeParameters().get("param2"));

+        assertEquals("value3", bd.getContentTypeParameters().get("param3"));

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/plain; "

+                + "param1= \" value with\tspaces \" ; "

+                + "param2=\"\\\"value4 with escaped \\\" \\\"\";"));

+        assertEquals(2, bd.getContentTypeParameters().size());

+        assertEquals(" value with\tspaces ", bd.getContentTypeParameters().get("param1"));

+        assertEquals("\"value4 with escaped \" \"", bd.getContentTypeParameters().get("param2"));

+        

+        /*

+         * Make sure escaped characters (except ") are still escaped.

+         * The parameter value should be \n\"

+         */

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/plain; param=\"\\n\\\\\\\"\""));

+        assertEquals(1, bd.getContentTypeParameters().size());

+        assertEquals("\\n\\\"", bd.getContentTypeParameters().get("param"));

+    }

+    

+    public void testAddField() {

+        MutableBodyDescriptor bd = null;

+        

+        /*

+         * Make sure that only the first Content-Type header added is used.

+         */

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/plain; charset=ISO-8859-1"));

+        assertEquals("text/plain", bd.getMimeType());

+        assertEquals("iso-8859-1", bd.getCharset());

+        bd.addField(new TestField("Content-Type ", "text/html; charset=us-ascii"));

+        assertEquals("text/plain", bd.getMimeType());

+        assertEquals("iso-8859-1", bd.getCharset());

+    }

+    

+    public void testGetMimeType() {

+        MutableBodyDescriptor bd = null;

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/PLAIN"));

+        assertEquals("text/plain", bd.getMimeType());

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/PLAIN;"));

+        assertEquals("text/plain", bd.getMimeType());

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("content-type", "   TeXt / html   "));

+        assertEquals("text/html", bd.getMimeType());

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("CONTENT-TYPE", "   x-app/yada ;  param = yada"));

+        assertEquals("x-app/yada", bd.getMimeType());

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("CONTENT-TYPE", "   yada"));

+        assertEquals("text/plain", bd.getMimeType());

+        

+        /*

+         * Make sure that only the first Content-Type header added is used.

+         */

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type ", "text/plain"));

+        assertEquals("text/plain", bd.getMimeType());

+        bd.addField(new TestField("Content-Type ", "text/html"));

+        assertEquals("text/plain", bd.getMimeType());

+        

+        /*

+         * Implicit mime types.

+         */

+        MutableBodyDescriptor child = null;

+        MutableBodyDescriptor parent = null;

+        

+        parent = newBodyDescriptor();

+        parent.addField(new TestField("Content-Type", "mutlipart/alternative; boundary=foo"));

+        

+        child = newBodyDescriptor(parent);

+        assertEquals("text/plain", child.getMimeType());

+        child.addField(new TestField("Content-Type", " child/type"));

+        assertEquals("child/type", child.getMimeType());

+        

+        parent = newBodyDescriptor();

+        parent.addField(new TestField("Content-Type", "multipart/digest; boundary=foo"));

+        

+        child = newBodyDescriptor(parent);

+        assertEquals("message/rfc822", child.getMimeType());

+        child.addField(new TestField("Content-Type", " child/type"));

+        assertEquals("child/type", child.getMimeType());

+        

+    }

+    

+    public void testParameters() {

+        MutableBodyDescriptor bd = null;

+

+        /*

+         * Test charset.

+         */

+        bd = newBodyDescriptor();

+        assertEquals("us-ascii", bd.getCharset());

+        bd.addField(new TestField("Content-Type ", "text/type; charset=ISO-8859-1"));

+        assertEquals("iso-8859-1", bd.getCharset());

+        

+        bd = newBodyDescriptor();

+        assertEquals("us-ascii", bd.getCharset());

+        bd.addField(new TestField("Content-Type ", "text/type"));

+        assertEquals("us-ascii", bd.getCharset());

+        

+        /*

+         * Test boundary.

+         */

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type", "text/html; boundary=yada yada"));

+        assertNull(bd.getBoundary());

+

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type", "multipart/yada; boundary=yada"));

+        assertEquals("yada", bd.getBoundary());

+

+        /*

+         * Test some weird parameters.

+         */

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type", "multipart/yada; boundary=yada yada"));

+        assertEquals("yada", bd.getBoundary());

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type", "multipart/yada; boUNdarY= ya:*da; \tcharset\t =  big5"));

+        assertEquals("ya:*da", bd.getBoundary());

+        assertEquals("big5", bd.getCharset());

+        

+        bd = newBodyDescriptor();

+        bd.addField(new TestField("Content-Type", "multipart/yada; boUNdarY= \"ya \\\"\\\"\tda \\\"\"; "

+                            + "\tcharset\t =  \"\\\"hepp\\\"  =us\t-ascii\""));

+        assertEquals("ya \"\"\tda \"", bd.getBoundary());

+        assertEquals("\"hepp\"  =us\t-ascii", bd.getCharset());

+        

+    }

+    

+    public void testGetContentLength() throws Exception {

+        MutableBodyDescriptor bd = null;

+

+        bd = newBodyDescriptor();

+        assertEquals(-1, bd.getContentLength());

+

+        bd.addField(new TestField("Content-Length", "9901"));

+        assertEquals(9901, bd.getContentLength());

+

+        // only the first content-length counts

+        bd.addField(new TestField("Content-Length", "1239901"));

+        assertEquals(9901, bd.getContentLength());

+    }

+    

+    public void testDoDefaultToUsAsciiWhenUntyped() throws Exception {

+        MutableBodyDescriptor descriptor = newBodyDescriptor();

+        descriptor.addField(new TestField("To", "me@example.org"));

+        assertEquals("us-ascii", descriptor.getCharset());

+    }

+

+    public void testDoNotDefaultToUsAsciiForNonTextTypes() throws Exception {

+        MutableBodyDescriptor descriptor = newBodyDescriptor();

+        descriptor.addField(new TestField("Content-Type", "image/png; name=blob.png"));

+        assertNull(descriptor.getCharset());

+    }

+    

+    private static final class TestField implements Field {

+

+        private final String name;

+        private final String body;

+

+        public TestField(String name, String body){

+            this.name = name;

+            this.body = body;

+        }

+        

+        public String getName() {

+            return name;

+        }

+

+        public String getBody() {

+            return body;

+        }

+

+        public ByteSequence getRaw() {

+            throw new UnsupportedOperationException();

+        }

+        

+    }

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptorTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptorTest.java
new file mode 100644
index 0000000..aa3d944
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/DefaultBodyDescriptorTest.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.descriptor;
+
+import org.apache.james.mime4j.descriptor.DefaultBodyDescriptor;
+
+public class DefaultBodyDescriptorTest extends BaseTestForBodyDescriptors {
+    @Override
+    protected MutableBodyDescriptor newBodyDescriptor() {
+        return new DefaultBodyDescriptor();
+    }
+
+    @Override
+    protected MutableBodyDescriptor newBodyDescriptor(BodyDescriptor parent) {
+        return new DefaultBodyDescriptor(parent);
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptorTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptorTest.java
new file mode 100644
index 0000000..8b861b0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/descriptor/MaximalBodyDescriptorTest.java
@@ -0,0 +1,190 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.descriptor;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.james.mime4j.ExampleMail;
+import org.apache.james.mime4j.descriptor.MaximalBodyDescriptor;
+import org.apache.james.mime4j.field.datetime.DateTime;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+public class MaximalBodyDescriptorTest extends BaseTestForBodyDescriptors {
+
+    MimeTokenStream parser;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        parser = MimeTokenStream.createMaximalDescriptorStream();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testMimeVersionDefault() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.RFC822_SIMPLE_BYTES);
+        assertEquals(1, descriptor.getMimeMajorVersion());
+        assertEquals(0, descriptor.getMimeMinorVersion());
+        assertNull(descriptor.getMimeVersionParseException());
+    }
+    
+    public void testMimeVersion() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_ASCII_COMMENT_IN_MIME_VERSION_BYTES);
+        assertEquals(2, descriptor.getMimeMajorVersion());
+        assertEquals(4, descriptor.getMimeMinorVersion());
+        assertNull(descriptor.getMimeVersionParseException());
+    }
+    
+    public void testContentId() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_8859_BYTES);
+        assertEquals(1, descriptor.getMimeMajorVersion());
+        assertEquals(0, descriptor.getMimeMinorVersion());
+        assertNull(descriptor.getMimeVersionParseException());
+        assertEquals(ExampleMail.CONTENT_ID, descriptor.getContentId());
+    }
+
+    public void testContentDescription() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_8859_BYTES);
+        assertEquals(1, descriptor.getMimeMajorVersion());
+        assertEquals(0, descriptor.getMimeMinorVersion());
+        assertNull(descriptor.getMimeVersionParseException());
+        assertEquals(ExampleMail.CONTENT_DESCRIPTION, descriptor.getContentDescription());
+    }
+    
+    public void testMimeVersionHeaderBreak() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_ASCII_MIME_VERSION_SPANS_TWO_LINES_BYTES);
+        assertEquals(4, descriptor.getMimeMajorVersion());
+        assertEquals(1, descriptor.getMimeMinorVersion());
+        assertNull(descriptor.getMimeVersionParseException());
+    }
+    
+    public void testContentDispositionType() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_BASE64_LATIN1_BYTES);
+        assertEquals("inline", descriptor.getContentDispositionType());
+    }
+    
+    public void testContentDispositionTypeCaseConversion() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_BASE64_LATIN1_BYTES);
+        assertEquals("Should be converted to lower case", "inline", descriptor.getContentDispositionType());
+        assertNotNull(descriptor.getContentDispositionParameters());
+        assertEquals(0, descriptor.getContentDispositionParameters().size());
+    }
+    
+    public void testContentDispositionParameters() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_WITH_CONTENT_DISPOSITION_PARAMETERS_BYTES);
+        assertEquals("inline", descriptor.getContentDispositionType());
+        assertNotNull(descriptor.getContentDispositionParameters());
+        assertEquals(3, descriptor.getContentDispositionParameters().size());
+        assertEquals("value", descriptor.getContentDispositionParameters().get("param"));
+        assertEquals("1", descriptor.getContentDispositionParameters().get("one"));
+        assertEquals("bar", descriptor.getContentDispositionParameters().get("foo"));
+    }
+    
+    public void testContentDispositionStandardParameters() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES, 1);
+        assertEquals("attachment", descriptor.getContentDispositionType());
+        assertNotNull(descriptor.getContentDispositionParameters());
+        assertEquals(5, descriptor.getContentDispositionParameters().size());
+        assertEquals("blob.png", descriptor.getContentDispositionFilename());
+        assertEquals(new DateTime("2008", 6, 21, 15, 32, 18, 0), descriptor.getContentDispositionModificationDate());
+        assertEquals(new DateTime("2008", 6, 20, 10, 15, 9, 0), descriptor.getContentDispositionCreationDate());
+        assertEquals(new DateTime("2008", 6, 22, 12, 8, 56, 0), descriptor.getContentDispositionReadDate());
+        assertEquals(10234, descriptor.getContentDispositionSize());
+    }
+    
+    public void testLanguageParameters() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES, 3);
+        assertNotNull(descriptor.getContentLanguage());
+        assertEquals(3, descriptor.getContentLanguage().size());
+        assertEquals("en", descriptor.getContentLanguage().get(0));
+        assertEquals("en-US", descriptor.getContentLanguage().get(1));
+        assertEquals("en-CA", descriptor.getContentLanguage().get(2));
+    }
+    
+    public void testContentLocationRelativeUrl() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.MULTIPART_WITH_CONTENT_LOCATION_BYTES, 0);
+        assertEquals("relative/url", descriptor.getContentLocation());
+    }
+    
+    public void testContentLocationAbsoluteUrl() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.MULTIPART_WITH_CONTENT_LOCATION_BYTES, 1);
+        assertEquals("http://www.example.org/absolute/rhubard.txt", descriptor.getContentLocation());
+    }
+    
+    public void testContentLocationWithComment() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.MULTIPART_WITH_CONTENT_LOCATION_BYTES, 3);
+        assertEquals("http://www.example.org/absolute/comments/rhubard.txt", descriptor.getContentLocation());
+    }
+    
+    public void testContentLocationFoldedUrl() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.MULTIPART_WITH_CONTENT_LOCATION_BYTES, 4);
+        assertEquals("http://www.example.org/this/is/a/very/long/url/split/over/two/lines/", descriptor.getContentLocation());
+    }
+    
+    public void testContentMD5Url() throws Exception {
+        MaximalBodyDescriptor descriptor = describe(ExampleMail.ONE_PART_MIME_WITH_CONTENT_DISPOSITION_PARAMETERS_BYTES);
+        assertEquals(ExampleMail.MD5_CONTENT, descriptor.getContentMD5Raw());
+    }
+    
+    private MaximalBodyDescriptor describe(byte[] mail, int zeroBasedPart) throws Exception {
+        ByteArrayInputStream bias = new ByteArrayInputStream(mail);
+        parser.parse(bias);
+        int state = parser.next();
+        while (state != MimeTokenStream.T_END_OF_STREAM && zeroBasedPart>=0) {
+            state = parser.next();
+            if (state == MimeTokenStream.T_BODY) {
+                --zeroBasedPart;
+            }
+        }
+        assertEquals(MimeTokenStream.T_BODY, state);
+        BodyDescriptor descriptor = parser.getBodyDescriptor();
+        assertNotNull(descriptor);
+        assertTrue("Parser is maximal so body descriptor should be maximal", descriptor instanceof MaximalBodyDescriptor);
+        return (MaximalBodyDescriptor) descriptor;
+    }
+    
+    private MaximalBodyDescriptor describe(byte[] mail) throws Exception {
+        ByteArrayInputStream bias = new ByteArrayInputStream(mail);
+        parser.parse(bias);
+        int state = parser.next();
+        while (state != MimeTokenStream.T_BODY && state != MimeTokenStream.T_END_OF_STREAM) 
+        {
+            state = parser.next();
+        }
+        assertEquals(MimeTokenStream.T_BODY, state);
+        BodyDescriptor descriptor = parser.getBodyDescriptor();
+        assertNotNull(descriptor);
+        assertTrue("Parser is maximal so body descriptor should be maximal", descriptor instanceof MaximalBodyDescriptor);
+        return (MaximalBodyDescriptor) descriptor;
+    }
+
+    @Override
+    protected MutableBodyDescriptor newBodyDescriptor() {
+        return new MaximalBodyDescriptor();
+    }
+
+    @Override
+    protected MutableBodyDescriptor newBodyDescriptor(BodyDescriptor parent) {
+        return new MaximalBodyDescriptor(parent);
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentDispositionFieldTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentDispositionFieldTest.java
new file mode 100644
index 0000000..fdb45d0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentDispositionFieldTest.java
@@ -0,0 +1,209 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import java.util.Date;

+

+import junit.framework.TestCase;

+

+import org.apache.log4j.BasicConfigurator;

+

+public class ContentDispositionFieldTest extends TestCase {

+

+    @Override

+    public void setUp() {

+        BasicConfigurator.resetConfiguration();

+        BasicConfigurator.configure();

+    }

+

+    public void testDispositionTypeWithSemiColonNoParams() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline;");

+        assertEquals("inline", f.getDispositionType());

+    }

+

+    public void testGetDispositionType() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment");

+        assertEquals("attachment", f.getDispositionType());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("content-disposition:   InLiNe   ");

+        assertEquals("inline", f.getDispositionType());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("CONTENT-DISPOSITION:   x-yada ;" + "  param = yada");

+        assertEquals("x-yada", f.getDispositionType());

+

+        f = (ContentDispositionField) AbstractField.parse("CONTENT-DISPOSITION:   ");

+        assertEquals("", f.getDispositionType());

+    }

+

+    public void testGetParameter() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("CONTENT-DISPOSITION:   inline ;"

+                        + "  filename=yada yada");

+        assertEquals("yada", f.getParameter("filename"));

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: x-yada;"

+                        + "  fileNAme= \"ya:\\\"*da\"; " + "\tSIZE\t =  1234");

+        assertEquals("ya:\"*da", f.getParameter("filename"));

+        assertEquals("1234", f.getParameter("size"));

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: x-yada;  "

+                        + "fileNAme= \"ya \\\"\\\"\tda \\\"\"; "

+                        + "\tx-Yada\t =  \"\\\"hepp\\\"  =us\t-ascii\"");

+        assertEquals("ya \"\"\tda \"", f.getParameter("filename"));

+        assertEquals("\"hepp\"  =us\t-ascii", f.getParameter("x-yada"));

+    }

+

+    public void testIsDispositionType() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField.parse("Content-Disposition:INline");

+        assertTrue(f.isDispositionType("InLiNe"));

+        assertFalse(f.isDispositionType("NiLiNe"));

+        assertTrue(f.isInline());

+        assertFalse(f.isAttachment());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment");

+        assertTrue(f.isDispositionType("ATTACHMENT"));

+        assertFalse(f.isInline());

+        assertTrue(f.isAttachment());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: x-something");

+        assertTrue(f.isDispositionType("x-SomeThing"));

+        assertFalse(f.isInline());

+        assertFalse(f.isAttachment());

+    }

+

+    public void testGetFilename() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; filename=yada.txt");

+        assertEquals("yada.txt", f.getFilename());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; filename=yada yada.txt");

+        assertEquals("yada", f.getFilename());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; filename=\"yada yada.txt\"");

+        assertEquals("yada yada.txt", f.getFilename());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline");

+        assertNull(f.getFilename());

+    }

+

+    public void testGetCreationDate() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; "

+                        + "creation-date=\"Tue, 01 Jan 1970 00:00:00 +0000\"");

+        assertEquals(new Date(0), f.getCreationDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; "

+                        + "creation-date=Tue, 01 Jan 1970 00:00:00 +0000");

+        assertNull(f.getCreationDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment");

+        assertNull(f.getCreationDate());

+    }

+

+    public void testGetModificationDate() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; "

+                        + "modification-date=\"Tue, 01 Jan 1970 00:00:00 +0000\"");

+        assertEquals(new Date(0), f.getModificationDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; "

+                        + "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"");

+        assertEquals(new Date(855782991000l), f.getModificationDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; "

+                        + "modification-date=yesterday");

+        assertNull(f.getModificationDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment");

+        assertNull(f.getModificationDate());

+    }

+

+    public void testGetReadDate() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; "

+                        + "read-date=\"Tue, 01 Jan 1970 00:00:00 +0000\"");

+        assertEquals(new Date(0), f.getReadDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: inline; read-date=");

+        assertNull(f.getReadDate());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment");

+        assertNull(f.getReadDate());

+    }

+

+    public void testGetSize() throws Exception {

+        ContentDispositionField f = null;

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment; size=0");

+        assertEquals(0, f.getSize());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment; size=matters");

+        assertEquals(-1, f.getSize());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment");

+        assertEquals(-1, f.getSize());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment; size=-12");

+        assertEquals(-1, f.getSize());

+

+        f = (ContentDispositionField) AbstractField

+                .parse("Content-Disposition: attachment; size=12");

+        assertEquals(12, f.getSize());

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentTransferEncodingFieldTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentTransferEncodingFieldTest.java
new file mode 100644
index 0000000..ee97c9b
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentTransferEncodingFieldTest.java
@@ -0,0 +1,68 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.field.ContentTransferEncodingField;

+import org.apache.james.mime4j.field.AbstractField;

+

+import junit.framework.TestCase;

+

+public class ContentTransferEncodingFieldTest extends TestCase {

+

+    public void testGetEncoding() throws Exception {

+        ContentTransferEncodingField f = null;

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding: 8bit");

+        assertEquals("8bit", f.getEncoding());

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding:    BaSE64   ");

+        assertEquals("base64", f.getEncoding());

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding:       ");

+        assertEquals("", f.getEncoding());

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding:");

+        assertEquals("", f.getEncoding());

+    }

+    

+    public void testGetEncodingStatic() throws Exception {

+        ContentTransferEncodingField f = null;

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding: 8bit");

+        assertEquals("8bit", ContentTransferEncodingField.getEncoding(f));

+        

+        f = null;

+        assertEquals("7bit", ContentTransferEncodingField.getEncoding(f));

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding:       ");

+        assertEquals("7bit", ContentTransferEncodingField.getEncoding(f));

+        

+        f = (ContentTransferEncodingField) 

+                    AbstractField.parse("Content-Transfer-Encoding:");

+        assertEquals("7bit", ContentTransferEncodingField.getEncoding(f));

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentTypeFieldTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentTypeFieldTest.java
new file mode 100644
index 0000000..6eeb193
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/ContentTypeFieldTest.java
@@ -0,0 +1,111 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.field.ContentTypeField;

+import org.apache.james.mime4j.field.AbstractField;

+import org.apache.log4j.BasicConfigurator;

+

+import junit.framework.TestCase;

+

+public class ContentTypeFieldTest extends TestCase {

+

+    @Override

+    public void setUp() {

+        BasicConfigurator.resetConfiguration();

+        BasicConfigurator.configure();

+    }

+    

+    public void testMimeTypeWithSemiColonNoParams() throws Exception  {

+        ContentTypeField f = null;

+        

+        f = (ContentTypeField) AbstractField.parse("Content-Type: text/html;");

+        assertEquals("text/html", f.getMimeType());

+    }

+    

+    public void testGetMimeType() throws Exception {

+        ContentTypeField f = null;

+        

+        f = (ContentTypeField) AbstractField.parse("Content-Type: text/PLAIN");

+        assertEquals("text/plain", f.getMimeType());

+        

+        f = (ContentTypeField) AbstractField.parse("content-type:   TeXt / html   ");

+        assertEquals("text/html", f.getMimeType());

+        

+        f = (ContentTypeField) AbstractField.parse("CONTENT-TYPE:   x-app/yada ;"

+                                                    + "  param = yada");

+        assertEquals("x-app/yada", f.getMimeType());

+        

+        f = (ContentTypeField) AbstractField.parse("CONTENT-TYPE:   yada");

+        assertEquals("", f.getMimeType());

+    }

+    

+    public void testGetMimeTypeStatic() throws Exception {

+        ContentTypeField child = null;

+        ContentTypeField parent = null;

+        

+        child = (ContentTypeField) AbstractField.parse("Content-Type: child/type");

+        parent = (ContentTypeField) AbstractField.parse("Content-Type: parent/type");

+        assertEquals("child/type", ContentTypeField.getMimeType(child, parent));

+        

+        child = null;

+        parent = (ContentTypeField) AbstractField.parse("Content-Type: parent/type");

+        assertEquals("text/plain", ContentTypeField.getMimeType(child, parent));

+        parent = (ContentTypeField) AbstractField.parse("Content-Type: multipart/digest");

+        assertEquals("message/rfc822", ContentTypeField.getMimeType(child, parent));

+        

+        child = (ContentTypeField) AbstractField.parse("Content-Type:");

+        parent = (ContentTypeField) AbstractField.parse("Content-Type: parent/type");

+        assertEquals("text/plain", ContentTypeField.getMimeType(child, parent));

+        parent = (ContentTypeField) AbstractField.parse("Content-Type: multipart/digest");

+        assertEquals("message/rfc822", ContentTypeField.getMimeType(child, parent));

+    }

+    

+    public void testGetCharsetStatic() throws Exception {

+        ContentTypeField f = null;

+        

+        f = (ContentTypeField) AbstractField.parse("Content-Type: some/type; charset=iso8859-1");

+        assertEquals("iso8859-1", ContentTypeField.getCharset(f));

+        

+        f = (ContentTypeField) AbstractField.parse("Content-Type: some/type;");

+        assertEquals("us-ascii", ContentTypeField.getCharset(f));

+    }

+    

+    public void testGetParameter() throws Exception {

+        ContentTypeField f = null;

+        

+        f = (ContentTypeField) AbstractField.parse("CONTENT-TYPE:   text / html ;"

+                                                + "  boundary=yada yada");

+        assertEquals("yada", f.getParameter("boundary"));

+        

+        f = (ContentTypeField) AbstractField.parse("Content-Type: x-app/yada;"

+                                                + "  boUNdarY= \"ya:\\\"*da\"; "

+                                                + "\tcharset\t =  us-ascii");

+        assertEquals("ya:\"*da", f.getParameter("boundary"));

+        assertEquals("us-ascii", f.getParameter("charset"));

+        

+        f = (ContentTypeField) AbstractField.parse("Content-Type: x-app/yada;  "

+                            + "boUNdarY= \"ya \\\"\\\"\tda \\\"\"; "

+                            + "\tcharset\t =  \"\\\"hepp\\\"  =us\t-ascii\"");

+        assertEquals("ya \"\"\tda \"", f.getParameter("boundary"));

+        assertEquals("\"hepp\"  =us\t-ascii", f.getParameter("charset"));

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/FieldTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/FieldTest.java
new file mode 100644
index 0000000..a2ea428
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/FieldTest.java
@@ -0,0 +1,63 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.field.ContentTransferEncodingField;

+import org.apache.james.mime4j.field.ContentTypeField;

+import org.apache.james.mime4j.field.AbstractField;

+import org.apache.james.mime4j.field.UnstructuredField;

+import org.apache.james.mime4j.parser.Field;

+

+import junit.framework.TestCase;

+

+public class FieldTest extends TestCase {

+

+    public void testGetName() throws Exception {

+        Field f = null;

+        

+        f = AbstractField.parse("Subject: Yada yada yada");

+        assertEquals("Testing simple field", "Subject", f.getName());

+        

+        f = AbstractField.parse("X-yada-yada: Yada yada yada");

+        assertEquals("Testing an X- field", "X-yada-yada", f.getName());

+        

+        try {

+            f = AbstractField.parse("Yada yada yada");

+            fail("MimeException not thrown when using an invalid field");

+        } catch (MimeException e) {

+        }

+    }

+

+    public void testParse() throws Exception {

+        Field f = null;

+        

+        f = AbstractField.parse("Subject: Yada yada yada");

+        assertTrue("Field should be UnstructuredField", 

+                        f instanceof UnstructuredField);

+        f = AbstractField.parse("Content-Type: text/plain");

+        assertTrue("Field should be ContentTypeField", 

+                        f instanceof ContentTypeField);

+        f = AbstractField.parse("Content-Transfer-Encoding: 7bit");

+        assertTrue("Field should be ContentTransferEncodingField", 

+                        f instanceof ContentTransferEncodingField);

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/FieldsTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/FieldsTest.java
new file mode 100644
index 0000000..95286d4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/FieldsTest.java
@@ -0,0 +1,381 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.field.address.Group;
+import org.apache.james.mime4j.field.address.Mailbox;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.util.MimeUtil;
+
+public class FieldsTest extends TestCase {
+
+    public void testContentTypeString() throws Exception {
+        ContentTypeField field = Fields.contentType("multipart/mixed; "
+                + "boundary=\"-=Part.0.37877968dd4f6595.11eccf0271c"
+                + ".2dce5678cbc933d5=-\"");
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Type: multipart/mixed;\r\n "
+                + "boundary=\"-=Part.0.37877968dd4f6595.11eccf0271c"
+                + ".2dce5678cbc933d5=-\"";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+    }
+
+    public void testContentTypeStringParameters() throws Exception {
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("boundary",
+                "-=Part.0.37877968dd4f6595.11eccf0271c.2dce5678cbc933d5=-");
+        ContentTypeField field = Fields.contentType("multipart/mixed",
+                parameters);
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Type: multipart/mixed;\r\n "
+                + "boundary=\"-=Part.0.37877968dd4f6595.11eccf0271c"
+                + ".2dce5678cbc933d5=-\"";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+    }
+
+    public void testContentTypeStringParametersWithSpaces() throws Exception {
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("param", "value with space chars");
+        ContentTypeField field = Fields.contentType("multipart/mixed",
+                parameters);
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Type: multipart/mixed; "
+                + "param=\"value with space chars\"";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+    }
+
+    public void testContentTypeStringNullParameters() throws Exception {
+        ContentTypeField field = Fields.contentType("text/plain", null);
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Type: text/plain";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+    }
+
+    public void testInvalidContentType() throws Exception {
+        ContentTypeField field = Fields.contentType("multipart/mixed; "
+                + "boundary=-=Part.0.37877968dd4f6595.11eccf0271c"
+                + ".2dce5678cbc933d5=-");
+        assertFalse(field.isValidField());
+
+        assertEquals("multipart/mixed", field.getMimeType());
+    }
+
+    public void testContentTransferEncoding() throws Exception {
+        ContentTransferEncodingField field = Fields
+                .contentTransferEncoding("base64");
+        assertTrue(field.isValidField());
+
+        assertEquals("Content-Transfer-Encoding: base64",
+                decode(field.getRaw()));
+    }
+
+    public void testContentDispositionString() throws Exception {
+        ContentDispositionField field = Fields.contentDisposition("inline; "
+                + "filename=\"testing 1 2.dat\"; size=12345; "
+                + "creation-date=\"Thu, 1 Jan 1970 00:00:00 +0000\"");
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Disposition: inline; filename="
+                + "\"testing 1 2.dat\"; size=12345;\r\n creation-date="
+                + "\"Thu, 1 Jan 1970 00:00:00 +0000\"";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+    }
+
+    public void testContentDispositionStringParameters() throws Exception {
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("creation-date", MimeUtil.formatDate(new Date(0),
+                TimeZone.getTimeZone("GMT")));
+        ContentDispositionField field = Fields.contentDisposition("attachment",
+                parameters);
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Disposition: attachment; "
+                + "creation-date=\"Thu, 1 Jan 1970 00:00:00\r\n +0000\"";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+
+        assertEquals(new Date(0), field.getCreationDate());
+    }
+
+    public void testContentDispositionStringNullParameters() throws Exception {
+        ContentDispositionField field = Fields.contentDisposition("inline",
+                (Map<String, String>) null);
+        assertTrue(field.isValidField());
+
+        String expectedRaw = "Content-Disposition: inline";
+        assertEquals(expectedRaw, decode(field.getRaw()));
+    }
+
+    public void testContentDispositionFilename() throws Exception {
+        ContentDispositionField field = Fields.contentDisposition("attachment",
+                "some file.dat");
+        assertTrue(field.isValidField());
+
+        assertEquals("attachment", field.getDispositionType());
+        assertEquals("some file.dat", field.getFilename());
+    }
+
+    public void testContentDispositionFilenameSize() throws Exception {
+        ContentDispositionField field = Fields.contentDisposition("attachment",
+                "some file.dat", 300);
+        assertTrue(field.isValidField());
+
+        assertEquals("attachment", field.getDispositionType());
+        assertEquals("some file.dat", field.getFilename());
+        assertEquals(300, field.getSize());
+    }
+
+    public void testContentDispositionFilenameSizeDate() throws Exception {
+        ContentDispositionField field = Fields.contentDisposition("attachment",
+                "some file.dat", 300, new Date(1000), new Date(2000), new Date(
+                        3000));
+        assertTrue(field.isValidField());
+
+        assertEquals("attachment", field.getDispositionType());
+        assertEquals("some file.dat", field.getFilename());
+        assertEquals(300, field.getSize());
+        assertEquals(new Date(1000), field.getCreationDate());
+        assertEquals(new Date(2000), field.getModificationDate());
+        assertEquals(new Date(3000), field.getReadDate());
+    }
+
+    public void testInvalidContentDisposition() throws Exception {
+        ContentDispositionField field = Fields.contentDisposition("inline; "
+                + "filename=some file.dat");
+        assertFalse(field.isValidField());
+
+        assertEquals("inline", field.getDispositionType());
+    }
+
+    public void testDateStringDateTimeZone() throws Exception {
+        DateTimeField field = Fields.date("Date", new Date(0), TimeZone
+                .getTimeZone("GMT"));
+        assertTrue(field.isValidField());
+
+        assertEquals("Date: Thu, 1 Jan 1970 00:00:00 +0000", decode(field
+                .getRaw()));
+        assertEquals(new Date(0), field.getDate());
+
+        field = Fields.date("Resent-Date", new Date(0), TimeZone
+                .getTimeZone("GMT+1"));
+        assertTrue(field.isValidField());
+
+        assertEquals("Resent-Date: Thu, 1 Jan 1970 01:00:00 +0100",
+                decode(field.getRaw()));
+        assertEquals(new Date(0), field.getDate());
+    }
+
+    public void testDateDST() throws Exception {
+        long millis = 1216221153000l;
+        DateTimeField field = Fields.date("Date", new Date(millis), TimeZone
+                .getTimeZone("CET"));
+        assertTrue(field.isValidField());
+
+        assertEquals("Date: Wed, 16 Jul 2008 17:12:33 +0200", decode(field
+                .getRaw()));
+        assertEquals(new Date(millis), field.getDate());
+    }
+
+    public void testMessageId() throws Exception {
+        Field messageId = Fields.messageId("acme.org");
+
+        String raw = ContentUtil.decode(messageId.getRaw());
+        assertTrue(raw.startsWith("Message-ID: <Mime4j."));
+        assertTrue(raw.endsWith("@acme.org>"));
+    }
+
+    public void testSubject() throws Exception {
+        assertEquals("Subject: ", decode(Fields.subject("").getRaw()));
+        assertEquals("Subject: test", decode(Fields.subject("test").getRaw()));
+        assertEquals("Subject: =?ISO-8859-1?Q?Sm=F8rebr=F8d?=", decode(Fields
+                .subject("Sm\370rebr\370d").getRaw()));
+
+        String seventyEight = "12345678901234567890123456789012345678901234567890123456789012345678";
+        assertEquals("Subject:\r\n " + seventyEight, decode(Fields.subject(
+                seventyEight).getRaw()));
+
+        String seventyNine = seventyEight + "9";
+        String expected = "Subject: =?US-ASCII?Q?1234567890123456789012345678901234?="
+                + "\r\n =?US-ASCII?Q?56789012345678901234567890123456789?=";
+        assertEquals(expected, decode(Fields.subject(seventyNine).getRaw()));
+    }
+
+    public void testSender() throws Exception {
+        MailboxField field = Fields.sender(Mailbox
+                .parse("JD <john.doe@acme.org>"));
+        assertEquals("Sender: JD <john.doe@acme.org>", decode(field.getRaw()));
+    }
+
+    public void testFrom() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("Mary Smith <mary@example.net>");
+
+        MailboxListField field = Fields.from(mailbox1);
+        assertEquals("From: JD <john.doe@acme.org>", decode(field.getRaw()));
+
+        field = Fields.from(mailbox1, mailbox2);
+        assertEquals("From: JD <john.doe@acme.org>, "
+                + "Mary Smith <mary@example.net>", decode(field.getRaw()));
+
+        field = Fields.from(Arrays.asList(mailbox1, mailbox2));
+        assertEquals("From: JD <john.doe@acme.org>, "
+                + "Mary Smith <mary@example.net>", decode(field.getRaw()));
+    }
+
+    public void testTo() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.org");
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+        Group group = new Group("The Does", mailbox1, mailbox2);
+
+        AddressListField field = Fields.to(group);
+        assertEquals("To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;", decode(field.getRaw()));
+
+        field = Fields.to(group, mailbox3);
+        assertEquals("To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary Smith\r\n <mary@example.net>",
+                decode(field.getRaw()));
+
+        field = Fields.to(Arrays.asList(group, mailbox3));
+        assertEquals("To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary Smith\r\n <mary@example.net>",
+                decode(field.getRaw()));
+    }
+
+    public void testCc() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.org");
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+        Group group = new Group("The Does", mailbox1, mailbox2);
+
+        AddressListField field = Fields.cc(group);
+        assertEquals("Cc: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;", decode(field.getRaw()));
+
+        field = Fields.cc(group, mailbox3);
+        assertEquals("Cc: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary Smith\r\n <mary@example.net>",
+                decode(field.getRaw()));
+
+        field = Fields.cc(Arrays.asList(group, mailbox3));
+        assertEquals("Cc: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary Smith\r\n <mary@example.net>",
+                decode(field.getRaw()));
+    }
+
+    public void testBcc() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.org");
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+        Group group = new Group("The Does", mailbox1, mailbox2);
+
+        AddressListField field = Fields.bcc(group);
+        assertEquals("Bcc: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;", decode(field.getRaw()));
+
+        field = Fields.bcc(group, mailbox3);
+        assertEquals("Bcc: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary Smith\r\n <mary@example.net>",
+                decode(field.getRaw()));
+
+        field = Fields.bcc(Arrays.asList(group, mailbox3));
+        assertEquals("Bcc: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary Smith\r\n <mary@example.net>",
+                decode(field.getRaw()));
+    }
+
+    public void testReplyTo() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.org");
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+        Group group = new Group("The Does", mailbox1, mailbox2);
+
+        AddressListField field = Fields.replyTo(group);
+        assertEquals("Reply-To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;", decode(field.getRaw()));
+
+        field = Fields.replyTo(group, mailbox3);
+        assertEquals("Reply-To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary\r\n Smith <mary@example.net>",
+                decode(field.getRaw()));
+
+        field = Fields.replyTo(Arrays.asList(group, mailbox3));
+        assertEquals("Reply-To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary\r\n Smith <mary@example.net>",
+                decode(field.getRaw()));
+    }
+
+    public void testMailbox() throws Exception {
+        MailboxField field = Fields.mailbox("Resent-Sender", Mailbox
+                .parse("JD <john.doe@acme.org>"));
+        assertEquals("Resent-Sender: JD <john.doe@acme.org>", decode(field
+                .getRaw()));
+    }
+
+    public void testMailboxList() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("Mary Smith <mary@example.net>");
+
+        MailboxListField field = Fields.mailboxList("Resent-From", Arrays
+                .asList(mailbox1, mailbox2));
+        assertEquals("Resent-From: JD <john.doe@acme.org>, "
+                + "Mary Smith <mary@example.net>", decode(field.getRaw()));
+    }
+
+    public void testAddressList() throws Exception {
+        Mailbox mailbox1 = Mailbox.parse("JD <john.doe@acme.org>");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.org");
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+        Group group = new Group("The Does", mailbox1, mailbox2);
+
+        AddressListField field = Fields.addressList("Resent-To", Arrays.asList(
+                group, mailbox3));
+        assertEquals("Resent-To: The Does: JD <john.doe@acme.org>, "
+                + "jane.doe@example.org;, Mary\r\n Smith <mary@example.net>",
+                decode(field.getRaw()));
+    }
+
+    public void testInvalidFieldName() throws Exception {
+        try {
+            Fields.date("invalid field name", new Date());
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private String decode(ByteSequence byteSequence) {
+        return ContentUtil.decode(byteSequence);
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/UnstructuredFieldTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/UnstructuredFieldTest.java
new file mode 100644
index 0000000..e78492e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/UnstructuredFieldTest.java
@@ -0,0 +1,42 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field;

+

+import org.apache.james.mime4j.field.AbstractField;

+import org.apache.james.mime4j.field.UnstructuredField;

+

+import junit.framework.TestCase;

+

+public class UnstructuredFieldTest extends TestCase {

+

+    public void testGetBody() throws Exception {

+        UnstructuredField f = null;

+        

+        f = (UnstructuredField) AbstractField.parse("Subject: Yada\r\n yada yada\r\n");

+        assertEquals("Testing folding value 1", "Yada yada yada", f.getValue());

+        

+        f = (UnstructuredField) AbstractField.parse("Subject:  \r\n\tyada");

+        assertEquals("Testing folding value 2", " \tyada", f.getValue());

+        

+        f = (UnstructuredField) AbstractField.parse("Subject:yada");

+        assertEquals("Testing value without a leading ' '", "yada", f.getValue());

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/address/AddressTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/address/AddressTest.java
new file mode 100644
index 0000000..8325a1d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/address/AddressTest.java
@@ -0,0 +1,485 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.address;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.field.address.parser.ParseException;

+

+import java.io.BufferedReader;

+import java.io.InputStream;

+import java.io.InputStreamReader;

+import java.io.PipedInputStream;

+import java.io.PipedOutputStream;

+import java.io.PrintStream;

+import java.io.PrintWriter;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

+

+import junit.framework.TestCase;

+

+public class AddressTest extends TestCase {

+

+    public void testExceptionTree() {

+        // make sure that our ParseException extends MimeException.

+        assertTrue(MimeException.class.isAssignableFrom(ParseException.class));

+    }

+

+    public void testParse1() throws ParseException {

+        AddressList addrList = AddressList.parse("John Doe <jdoe@machine(comment).  example>");

+        assertEquals(1, addrList.size());

+        Mailbox mailbox = (Mailbox)addrList.get(0);

+        assertEquals("John Doe", mailbox.getName());

+        assertEquals("jdoe", mailbox.getLocalPart());

+        assertEquals("machine.example", mailbox.getDomain());

+    }

+

+    public void testParse2() throws ParseException {

+        AddressList addrList = AddressList.parse("Mary Smith \t    \t\t  <mary@example.net>");

+        assertEquals(1, addrList.size());

+        Mailbox mailbox = (Mailbox)addrList.get(0);

+        assertEquals("Mary Smith", mailbox.getName());

+        assertEquals("mary", mailbox.getLocalPart());

+        assertEquals("example.net", mailbox.getDomain());

+    }

+

+    public void testEmptyGroup() throws ParseException {

+        AddressList addrList = AddressList.parse("undisclosed-recipients:;");

+        assertEquals(1, addrList.size());

+        Group group = (Group)addrList.get(0);

+        assertEquals(0, group.getMailboxes().size());

+        assertEquals("undisclosed-recipients", group.getName());

+    }

+

+    public void testMessyGroupAndMailbox() throws ParseException {

+        AddressList addrList = AddressList.parse("Marketing  folks :  Jane Smith < jane @ example . net >, \" Jack \\\"Jackie\\\" Jones \" < jjones@example.com > (comment(comment)); ,, (comment)  , <@example . net,@example(ignore\\)).com:(ignore)john@(ignore)example.net>");

+        assertEquals(2, addrList.size());

+

+        Group group = (Group)addrList.get(0);

+        assertEquals("Marketing  folks", group.getName());

+        assertEquals(2, group.getMailboxes().size());

+

+        Mailbox mailbox1 = group.getMailboxes().get(0);

+        Mailbox mailbox2 = group.getMailboxes().get(1);

+

+        assertEquals("Jane Smith", mailbox1.getName());

+        assertEquals("jane", mailbox1.getLocalPart());

+        assertEquals("example.net", mailbox1.getDomain());

+

+        assertEquals(" Jack \"Jackie\" Jones ", mailbox2.getName());

+        assertEquals("jjones", mailbox2.getLocalPart());

+        assertEquals("example.com", mailbox2.getDomain());

+

+        Mailbox mailbox = (Mailbox)addrList.get(1);

+        assertEquals("john", mailbox.getLocalPart());

+        assertEquals("example.net", mailbox.getDomain());

+        assertEquals(2, mailbox.getRoute().size());

+        assertEquals("example.net", mailbox.getRoute().get(0));

+        assertEquals("example.com", mailbox.getRoute().get(1));

+    }

+

+    public void testEmptyAddressList() throws ParseException {

+        assertEquals(0, AddressList.parse("  \t   \t ").size());

+        assertEquals(0, AddressList.parse("  \t  ,  , , ,,, , \t ").size());

+    }

+

+    public void testSimpleForm() throws ParseException {

+        AddressList addrList = AddressList.parse("\"a b c d e f g\" (comment) @example.net");

+        assertEquals(1, addrList.size());

+        Mailbox mailbox = (Mailbox)addrList.get(0);

+        assertEquals("a b c d e f g", mailbox.getLocalPart());

+        assertEquals("example.net", mailbox.getDomain());

+    }

+

+    public void testFlatten() throws ParseException {

+        AddressList addrList = AddressList.parse("dev : one@example.com, two@example.com; , ,,, marketing:three@example.com ,four@example.com;, five@example.com");

+        assertEquals(3, addrList.size());

+        assertEquals(5, addrList.flatten().size());

+    }

+

+    public void testTortureTest() throws ParseException {

+

+        // Source: http://mailformat.dan.info/headers/from.html

+        // (Commented out pending confirmation of legality--I think the local-part is illegal.) 

+        // AddressList.parse("\"Guy Macon\" <guymacon+\" http://www.guymacon.com/ \"00@spamcop.net>");

+

+        // Taken mostly from RFC822.

+

+        // Just make sure these are recognized as legal address lists;

+        // there shouldn't be any aspect of the RFC that is tested here

+        // but not in the other unit tests.

+

+        AddressList.parse("Alfred Neuman <Neuman@BBN-TENEXA>");

+        AddressList.parse("Neuman@BBN-TENEXA");

+        AddressList.parse("\"George, Ted\" <Shared@Group.Arpanet>");

+        AddressList.parse("Wilt . (the Stilt) Chamberlain@NBA.US");

+

+        // NOTE: In RFC822 8.1.5, the following example did not have "Galloping Gourmet"

+        // in double-quotes.  I can only assume this was a typo, since 6.2.4 specifically

+        // disallows spaces in unquoted local-part.

+        AddressList.parse("     Gourmets:  Pompous Person <WhoZiWhatZit@Cordon-Bleu>," +

+                "                Childs@WGBH.Boston, \"Galloping Gourmet\"@" +

+                "                ANT.Down-Under (Australian National Television)," +

+                "                Cheapie@Discount-Liquors;," +

+                "       Cruisers:  Port@Portugal, Jones@SEA;," +

+                "         Another@Somewhere.SomeOrg");

+

+        // NOTE: In RFC822 8.3.3, the following example ended with a lone ">" after

+        // Tops-20-Host.  I can only assume this was a typo, since 6.1 clearly shows

+        // ">" requires a matching "<".

+        AddressList.parse("Important folk:" +

+                "                   Tom Softwood <Balsa@Tree.Root>," +

+                "                   \"Sam Irving\"@Other-Host;," +

+                "                 Standard Distribution:" +

+                "                   /main/davis/people/standard@Other-Host," +

+                "                   \"<Jones>standard.dist.3\"@Tops-20-Host;");

+

+        // The following are from a Usenet post by Dan J. Bernstein:

+        // http://groups.google.com/groups?selm=1996Aug1418.21.01.28081%40koobera.math.uic.edu

+        AddressList.parse("\":sysmail\"@  Some-Group.\t         Some-Org, Muhammed.(I am  the greatest) Ali @(the)Vegas.WBA");

+        AddressList.parse("me@home.com (comment (nested (deeply\\))))");

+        AddressList.parse("mailing list: me@home.com, route two <you@work.com>, them@play.com ;");

+

+    }

+

+    public void testLexicalError() {

+        // ensure that TokenMgrError doesn't get thrown

+        try {

+            AddressList.parse(")");

+            fail("Expected parsing error");

+        }

+        catch (ParseException e) {

+

+        }

+    }

+    

+    public void testNullConstructorAndBadUsage() {

+        AddressList al = new AddressList(null, false);

+        assertEquals(0, al.size());

+        

+        try {

+            al.get(-1);

+            fail("Expected index out of bound exception!");

+        } catch (IndexOutOfBoundsException e) {

+        }

+        

+        try {

+            al.get(0);

+            fail("Expected index out of bound exception!");

+        } catch (IndexOutOfBoundsException e) {

+        }

+    }

+

+    

+    public void testAddressList() throws ParseException {

+        AddressList addlist = AddressList.parse("foo@example.com, bar@example.com, third@example.com");

+        List<Address> al = new ArrayList<Address>();

+        al.add(addlist.get(0));

+

+        // shared arraylist

+        AddressList dl = new AddressList(al, true);

+        assertEquals(1, dl.size());

+        al.add(addlist.get(1));

+        assertEquals(2, dl.size());

+        

+        // cloned arraylist

+        AddressList dlcopy = new AddressList(al, false);

+        assertEquals(2, dlcopy.size());

+        al.add(addlist.get(2));

+        assertEquals(2, dlcopy.size());

+        

+        // check route string

+        assertEquals(2, dlcopy.flatten().size());

+    }

+

+    public void testInteractiveMain() throws Exception {

+        PrintStream out_orig = System.out;

+        InputStream in_orig = System.in;

+        PrintStream err_orig = System.err;

+        try {

+            PipedOutputStream piped = new PipedOutputStream();

+            PipedInputStream newInput = new PipedInputStream(piped);

+            

+            PipedInputStream inOut = new PipedInputStream();

+            PrintStream outPs = new PrintStream(new PipedOutputStream(inOut));

+            BufferedReader outReader = new BufferedReader(new InputStreamReader(inOut));

+            PipedInputStream inErr = new PipedInputStream();

+            PrintStream errPs = new PrintStream(new PipedOutputStream(inErr));

+            BufferedReader errReader = new BufferedReader(new InputStreamReader(inErr));

+            

+            

+            System.setIn(newInput);

+            System.setOut(outPs);

+            System.setErr(errPs);

+            Thread t = new Thread() {

+                @Override

+                public void run() {

+                    try {

+                        AddressList.main(null);

+                    } catch (Exception e) {

+                        fail("Catched an exception in main: "+e);

+                    }

+                }

+            };

+            t.start();

+            

+            PrintWriter input = new PrintWriter(piped);

+            

+            input.write("Test <test@example.com>\r\n");

+            input.flush();

+

+            String out = outReader.readLine();

+            assertEquals("> Test <test@example.com>", out);

+

+            input.write("A <foo@example.com>\r\n");

+            input.flush();

+            

+            String out2 = outReader.readLine();

+            assertEquals("> A <foo@example.com>", out2);

+

+            input.write("\"Foo Bar\" <foo>\r\n");

+            input.flush();

+            

+            String out3 = errReader.readLine();

+            assertNotNull(out3);

+

+            input.write("quit\r\n");

+            input.flush();

+            

+            // we read 2 angular brackets because one was from the previous exception error.

+            String out4 = outReader.readLine();

+            assertEquals("> > Goodbye.", out4);

+

+            t.join();

+        } finally {

+            System.setIn(in_orig);

+            System.setOut(out_orig);

+            System.setErr(err_orig);

+        }

+    }

+

+    public void testEmptyDomainList() {

+        DomainList dl = new DomainList(null, false);

+        assertEquals(0, dl.size());

+        

+        try {

+            dl.get(-1);

+            fail("Expected index out of bound exception!");

+        } catch (IndexOutOfBoundsException e) {

+        }

+        

+        try {

+            dl.get(0);

+            fail("Expected index out of bound exception!");

+        } catch (IndexOutOfBoundsException e) {

+        }

+    }

+    

+    public void testDomainList() {

+        List<String> al = new ArrayList<String>();

+        al.add("example.com");

+

+        // shared arraylist

+        DomainList dl = new DomainList(al, true);

+        assertEquals(1, dl.size());

+        al.add("foo.example.com");

+        assertEquals(2, dl.size());

+        

+        // cloned arraylist

+        DomainList dlcopy = new DomainList(al, false);

+        assertEquals(2, dlcopy.size());

+        al.add("bar.example.com");

+        assertEquals(2, dlcopy.size());

+        

+        // check route string

+        assertEquals("@example.com,@foo.example.com", dlcopy.toRouteString());

+    }

+    

+

+    public void testEmptyMailboxList() {

+        MailboxList ml = new MailboxList(null, false);

+        assertEquals(0, ml.size());

+        

+        try {

+            ml.get(-1);

+            fail("Expected index out of bound exception!");

+        } catch (IndexOutOfBoundsException e) {

+        }

+        

+        try {

+            ml.get(0);

+            fail("Expected index out of bound exception!");

+        } catch (IndexOutOfBoundsException e) {

+        }

+    }

+

+    public void testMailboxList() {

+        List<Mailbox> al = new ArrayList<Mailbox>();

+        al.add(new Mailbox("local","example.com"));

+

+        // shared arraylist

+        MailboxList ml = new MailboxList(al, true);

+        assertEquals(1, ml.size());

+        al.add(new Mailbox("local2", "foo.example.com"));

+        assertEquals(2, ml.size());

+        

+        // cloned arraylist

+        MailboxList mlcopy = new MailboxList(al, false);

+        assertEquals(2, mlcopy.size());

+        al.add(new Mailbox("local3", "bar.example.com"));

+        assertEquals(2, mlcopy.size());

+        

+        mlcopy.print();

+    }

+    

+    public void testGroupSerialization() {

+        List<Mailbox> al = new ArrayList<Mailbox>();

+        al.add(new Mailbox("test", "example.com"));

+        al.add(new Mailbox("Foo!", "foo", "example.com"));

+        DomainList dl = new DomainList(new ArrayList<String>(Arrays.asList(new String[] {"foo.example.com"})), true);

+        Mailbox mailbox = new Mailbox("Foo Bar", dl, "foo2", "example.com");

+        assertSame(dl, mailbox.getRoute());

+        al.add(mailbox);

+        Group g = new Group("group", new MailboxList(al, false));

+        assertEquals("group: test@example.com, Foo! <foo@example.com>, Foo Bar <foo2@example.com>;", g.getDisplayString());

+    }

+    

+    public void testEmptyQuotedStringBeforeDotAtomInLocalPart() throws Exception {

+        /*

+         * This used to give a StringIndexOutOfBoundsException instead of the expected

+         * ParseException

+         */

+        try {

+            AddressList.parse("\"\"bar@bar.com");

+            fail("ParseException expected");

+        } catch (ParseException pe) {

+        }

+    }

+    

+    public void testMailboxGetEncodedString() throws Exception {

+        assertEquals("john.doe@acme.org", new Mailbox("john.doe", "acme.org")

+                .getEncodedString());

+        assertEquals("\"john doe\"@acme.org", new Mailbox("john doe",

+                "acme.org").getEncodedString());

+        assertEquals("John Doe <john.doe@acme.org>", new Mailbox("John Doe",

+                "john.doe", "acme.org").getEncodedString());

+        assertEquals("\"John Doe @Home\" <john.doe@acme.org>", new Mailbox(

+                "John Doe @Home", "john.doe", "acme.org").getEncodedString());

+        assertEquals("=?ISO-8859-1?Q?Hans_M=FCller?= <hans.mueller@acme.org>",

+                new Mailbox("Hans M\374ller", "hans.mueller", "acme.org")

+                        .getEncodedString());

+    }

+

+    public void testGroupGetEncodedString() throws Exception {

+        List<Mailbox> al = new ArrayList<Mailbox>();

+        al.add(new Mailbox("test", "example.com"));

+        al.add(new Mailbox("Foo!", "foo", "example.com"));

+        al.add(new Mailbox("Hans M\374ller", "hans.mueller", "acme.org"));

+        Group g = new Group("group @work", new MailboxList(al, false));

+        assertEquals("\"group @work\": test@example.com, "

+                + "Foo! <foo@example.com>, =?ISO-8859-1?Q?Hans_M=FCller?="

+                + " <hans.mueller@acme.org>;", g.getEncodedString());

+    }

+

+    public void testEmptyGroupGetEncodedString() throws Exception {

+        MailboxList emptyMailboxes = new MailboxList(null, true);

+        Group g = new Group("Undisclosed recipients", emptyMailboxes);

+        assertEquals("Undisclosed recipients:;", g.getEncodedString());

+    }

+

+    public void testParseAddress() throws Exception {

+        Address address = Address.parse("Mary Smith <mary@example.net>");

+        assertTrue(address instanceof Mailbox);

+        assertEquals("Mary Smith", ((Mailbox) address).getName());

+        assertEquals("mary@example.net", ((Mailbox) address).getAddress());

+

+        address = Address.parse("group: Mary Smith <mary@example.net>;");

+        assertTrue(address instanceof Group);

+        assertEquals("group", ((Group) address).getName());

+        assertEquals("Mary Smith", ((Group) address).getMailboxes().get(0)

+                .getName());

+        assertEquals("mary@example.net", ((Group) address).getMailboxes()

+                .get(0).getAddress());

+

+        try {

+            Group.parse("john.doe@acme.org, jane.doe@acme.org");

+            fail();

+        } catch (IllegalArgumentException expected) {

+        }

+    }

+    

+    public void testParseGroup() throws Exception {

+        Group group = Group

+                .parse("group: john.doe@acme.org, Mary Smith <mary@example.net>;");

+        assertEquals("group", group.getName());

+

+        MailboxList mailboxes = group.getMailboxes();

+        assertEquals(2, mailboxes.size());

+

+        Mailbox mailbox1 = mailboxes.get(0);

+        assertNull(mailbox1.getName());

+        assertEquals("john.doe@acme.org", mailbox1.getAddress());

+

+        Mailbox mailbox2 = mailboxes.get(1);

+        assertEquals("Mary Smith", mailbox2.getName());

+        assertEquals("mary@example.net", mailbox2.getAddress());

+

+        try {

+            Group.parse("john.doe@acme.org");

+            fail();

+        } catch (IllegalArgumentException expected) {

+        }

+

+        try {

+            Group.parse("g1: john.doe@acme.org;, g2: mary@example.net;");

+            fail();

+        } catch (IllegalArgumentException expected) {

+        }

+    }

+

+    public void testParseMailbox() throws Exception {

+        Mailbox mailbox1 = Mailbox.parse("john.doe@acme.org");

+        assertNull(mailbox1.getName());

+        assertEquals("john.doe@acme.org", mailbox1.getAddress());

+

+        Mailbox mailbox2 = Mailbox.parse("Mary Smith <mary@example.net>");

+        assertEquals("Mary Smith", mailbox2.getName());

+        assertEquals("mary@example.net", mailbox2.getAddress());

+

+        // non-ascii should be allowed in quoted strings

+        Mailbox mailbox3 = Mailbox

+                .parse("\"Hans M\374ller\" <hans.mueller@acme.org>");

+        assertEquals("Hans M\374ller", mailbox3.getName());

+        assertEquals("hans.mueller@acme.org", mailbox3.getAddress());

+

+        try {

+            Mailbox.parse("g: Mary Smith <mary@example.net>;");

+            fail();

+        } catch (IllegalArgumentException expected) {

+        }

+

+        try {

+            Mailbox.parse("Mary Smith <mary@example.net>, hans.mueller@acme.org");

+            fail();

+        } catch (IllegalArgumentException expected) {

+        }

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/contentdisposition/ContentDispositionTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/contentdisposition/ContentDispositionTest.java
new file mode 100644
index 0000000..4e135b7
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/contentdisposition/ContentDispositionTest.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field.contentdisposition;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.field.contentdisposition.parser.ParseException;
+
+public class ContentDispositionTest extends TestCase {
+
+    public void testExceptionTree() {
+        // make sure that our ParseException extends MimeException.
+        assertTrue(MimeException.class.isAssignableFrom(ParseException.class));
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/contenttype/ContentTypeTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/contenttype/ContentTypeTest.java
new file mode 100644
index 0000000..6ffd8c6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/contenttype/ContentTypeTest.java
@@ -0,0 +1,57 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.contenttype;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser;

+import org.apache.james.mime4j.field.contenttype.parser.ParseException;

+

+import java.io.StringReader;

+

+import junit.framework.TestCase;

+

+public class ContentTypeTest extends TestCase {

+

+    public void testExceptionTree() {

+        // make sure that our ParseException extends MimeException.

+        assertTrue(MimeException.class.isAssignableFrom(ParseException.class));

+    }

+

+    public void testContentType() throws ParseException {

+        test("one/two; three          =  four", "one", "two");

+        test("one/(foo)two; three          =  \"four\"", "one", "two");

+        test("one(foo)/two; three          =  (foo) four", "one", "two");

+        test("one/two; three          =  four", "one", "two");

+

+        // TODO: add more tests

+    }

+

+    private void test(String val, String expectedType, String expectedSubtype) throws ParseException {

+        ContentTypeParser parser = new ContentTypeParser(new StringReader(val));

+        parser.parseAll();

+

+        String type = parser.getType();

+        String subtype = parser.getSubType();

+

+        assertEquals(expectedType, type);

+        assertEquals(expectedSubtype, subtype);

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/datetime/DateTimeTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/datetime/DateTimeTest.java
new file mode 100644
index 0000000..162874d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/datetime/DateTimeTest.java
@@ -0,0 +1,109 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.field.datetime;

+

+import junit.framework.TestCase;

+

+import org.apache.james.mime4j.MimeException;

+import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;

+import org.apache.james.mime4j.field.datetime.parser.ParseException;

+

+import java.io.StringReader;

+

+public class DateTimeTest extends TestCase {

+    

+    public void testExceptionTree() {

+        // make sure that our ParseException extends MimeException.

+        assertTrue(MimeException.class.isAssignableFrom(ParseException.class));

+    }

+

+    public void testNormalDate() throws ParseException {

+        new DateTimeParser(new StringReader("Fri, 21 Nov 1997 09:55:06 -0600")).parseAll();

+        new DateTimeParser(new StringReader("21 Nov 97 09:55:06 GMT")).parseAll();

+

+

+        ensureAllEqual(new String[] {

+           "Fri, 21 Nov 1997 09:55:06 -0600", // baseline

+           "Fri, 21 Nov 97 09:55:06 -0600",   // 2-digit year

+           "Fri, 21 Nov 097 09:55:06 -0600",  // 3-digit year

+           "Fri, 21 Nov 1997 10:55:06 -0500", // shift time zone

+           "Fri, 21 Nov 1997 19:25:06 +0330", // shift time zone

+           "21 Nov 1997 09:55:06 -0600"       // omit day of week

+        });

+

+        ensureAllEqual(new String[] {

+            "Thu, 16 Sep 2019 14:37:22 +0000", // baseline

+            "Thu, 16 Sep 19 14:37:22 +0000",   // 2-digit year

+            "Thu, 16 Sep 119 14:37:22 +0000",  // 3-digit year

+            "Thu, 16 Sep 2019 14:37:22 -0000", // minus-zero zone

+            "Thu, 16 Sep 2019 14:37:22 GMT",   // alternate zone

+            "Thu, 16 Sep 2019 14:37:22 UT"     // alternate zone

+        });

+

+        ensureAllEqual(new String[] {

+            "Fri, 21 Nov 1997 12:00:00 GMT",

+            "Fri, 21 Nov 1997 07:00:00 EST",

+            "Fri, 21 Nov 1997 08:00:00 EDT",

+            "Fri, 21 Nov 1997 06:00:00 CST",

+            "Fri, 21 Nov 1997 07:00:00 CDT",

+            "Fri, 21 Nov 1997 05:00:00 MST",

+            "Fri, 21 Nov 1997 06:00:00 MDT",

+            "Fri, 21 Nov 1997 04:00:00 PST",

+            "Fri, 21 Nov 1997 05:00:00 PDT",

+

+            // make sure military zones are ignored, per RFC2822 instructions

+            "Fri, 21 Nov 1997 12:00:00 A",

+            "Fri, 21 Nov 1997 12:00:00 B",

+            "Fri, 21 Nov 1997 12:00:00 C",

+            "Fri, 21 Nov 1997 12:00:00 D",

+            "Fri, 21 Nov 1997 12:00:00 E",

+            "Fri, 21 Nov 1997 12:00:00 F",

+            "Fri, 21 Nov 1997 12:00:00 G",

+            "Fri, 21 Nov 1997 12:00:00 H",

+            "Fri, 21 Nov 1997 12:00:00 I",

+            "Fri, 21 Nov 1997 12:00:00 K",

+            "Fri, 21 Nov 1997 12:00:00 L",

+            "Fri, 21 Nov 1997 12:00:00 M",

+            "Fri, 21 Nov 1997 12:00:00 N",

+            "Fri, 21 Nov 1997 12:00:00 O",

+            "Fri, 21 Nov 1997 12:00:00 P",

+            "Fri, 21 Nov 1997 12:00:00 Q",

+            "Fri, 21 Nov 1997 12:00:00 R",

+            "Fri, 21 Nov 1997 12:00:00 S",

+            "Fri, 21 Nov 1997 12:00:00 T",

+            "Fri, 21 Nov 1997 12:00:00 U",

+            "Fri, 21 Nov 1997 12:00:00 V",

+            "Fri, 21 Nov 1997 12:00:00 W",

+            "Fri, 21 Nov 1997 12:00:00 X",

+            "Fri, 21 Nov 1997 12:00:00 Y",

+            "Fri, 21 Nov 1997 12:00:00 Z",

+        });

+    }

+

+    private void ensureAllEqual(String[] dateStrings) throws ParseException {

+        for (int i = 0; i < dateStrings.length - 1; i++) {

+            assertEquals(

+                    new DateTimeParser(new StringReader(dateStrings[i])).parseAll().getDate().getTime(),

+                    new DateTimeParser(new StringReader(dateStrings[i + 1])).parseAll().getDate().getTime()

+            );

+        }

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/mimeversion/MimeVersionParserTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/mimeversion/MimeVersionParserTest.java
new file mode 100644
index 0000000..0f2e9af
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/mimeversion/MimeVersionParserTest.java
@@ -0,0 +1,80 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field.mimeversion;
+
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.field.mimeversion.parser.MimeVersionParser;
+import org.apache.james.mime4j.field.mimeversion.parser.ParseException;
+
+public class MimeVersionParserTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testPlainLine() throws Exception {
+        check("2.4", 2, 4);
+        check("25.344", 25, 344);
+        check("0.1", 0, 1);
+        check("123234234.0", 123234234, 0);
+    }
+    
+    public void testLineWithComments() throws Exception {
+        check("2(A comment).4", 2, 4);
+        check("2(.8).4", 2, 4);
+        check("(A comment)2.4", 2, 4);
+        check("2.4(A comment)", 2, 4);
+        check("2.(A comment)4", 2, 4);
+    }
+    
+    public void testLineWithNestedComments() throws Exception {
+        check("2(4.45 ( Another ()comment () blah (Wobble(mix)))Whatever).4", 2, 4);
+    }
+    
+    public void testEmptyLine() throws Exception {
+        try {
+            parse("(This is just a comment)");
+            fail("Expected exception to be thrown");
+        } catch (ParseException e) {
+            //expected
+        }
+    }
+    
+    private void check(String input, int expectedMajorVersion, int expectedMinorVersion) throws Exception {
+        MimeVersionParser parser = parse(input);
+        assertEquals("Major version number", expectedMajorVersion, parser.getMajorVersion());
+        assertEquals("Minor version number", expectedMinorVersion, parser.getMinorVersion());
+    }
+
+    private MimeVersionParser parse(String input) throws ParseException {
+        MimeVersionParser parser = new MimeVersionParser(new StringReader(input));
+        parser.parseAll();
+        return parser;
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java
new file mode 100644
index 0000000..0e1d38d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/field/structured/StructuredFieldParserTest.java
@@ -0,0 +1,75 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.field.structured;
+
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.field.structured.parser.StructuredFieldParser;
+
+public class StructuredFieldParserTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testSimpleField() throws Exception {
+        final String string = "Field Value";
+        assertEquals(string, parse(string));
+    }
+    
+    public void testTrim() throws Exception {
+        final String string = "Field Value";
+        assertEquals(string, parse("    \t\r\n" + string + "  \t\r\n  "));
+    }
+    
+    public void testFolding() throws Exception {
+        assertEquals("Field Value", parse("Field \t\r\n  Value"));
+    }
+    
+    public void testQuotedString() throws Exception {
+        assertEquals("Field    Value", parse("\"Field    Value\""));
+        assertEquals("Field\t\r\nValue", parse("\"Field\t\r\nValue\""));
+        assertEquals("Field\t\r\nValue", parse("\"Field\t\r\n       \t       Value\""));
+    }
+    
+    public void testComments() throws Exception {
+        assertEquals("Field", parse("Fi(This is a comment)eld"));
+        assertEquals("Field Value", parse("Fi(This is a comment)eld (A (very (nested) )comment)Value"));
+    }
+    
+    public void testQuotedInComments() throws Exception {
+        assertEquals("Fi(This is a comment)eld", parse("\"Fi(This is a comment)eld\""));
+        assertEquals("Field Value", parse("Fi(This is a comment)eld (A (very (nested) )comment)Value"));
+    }
+    
+    private String parse(String in) throws Exception {
+        StructuredFieldParser parser = new StructuredFieldParser(new StringReader(in));
+        parser.setFoldingPreserved(true);
+        return parser.parse();
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamBufferTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamBufferTest.java
new file mode 100644
index 0000000..224653e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamBufferTest.java
@@ -0,0 +1,211 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class BufferedLineReaderInputStreamBufferTest extends TestCase {
+
+    public void testInvalidInput() throws Exception {
+        String text = "blah blah yada yada";
+        byte[] b1 = text.getBytes("US-ASCII");
+        String pattern = "blah";
+        byte[] b2 = pattern.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        
+        assertEquals('b', inbuffer.read());
+        assertEquals('l', inbuffer.read());
+        
+        try {
+            inbuffer.charAt(1);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.charAt(20);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf(b2, -1, 3);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf(b2, 1, 3);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf(b2, 2, -1);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf(b2, 2, 18);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        assertEquals(5, inbuffer.indexOf(b2, 2, 17));
+        try {
+            inbuffer.indexOf((byte)' ', -1, 3);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf((byte)' ', 1, 3);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf((byte)' ', 2, -1);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        try {
+            inbuffer.indexOf((byte)' ', 2, 18);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException expected) {
+        }
+        assertEquals(10, inbuffer.indexOf((byte)'y', 2, 17));
+    }
+      
+    public void testBasicOperations() throws Exception {
+        String text = "bla bla yada yada haha haha";
+        byte[] b1 = text.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        assertEquals(0, inbuffer.pos());
+        assertEquals(27, inbuffer.limit());
+        assertEquals(27, inbuffer.length());
+
+        inbuffer.read();
+        inbuffer.read();
+
+        assertEquals(2, inbuffer.pos());
+        assertEquals(27, inbuffer.limit());
+        assertEquals(25, inbuffer.length());
+        
+        byte[] tmp1 = new byte[3];
+        assertEquals(3, inbuffer.read(tmp1));
+
+        assertEquals(5, inbuffer.pos());
+        assertEquals(27, inbuffer.limit());
+        assertEquals(22, inbuffer.length());
+        
+        byte[] tmp2 = new byte[22];
+        assertEquals(22, inbuffer.read(tmp2));
+
+        assertEquals(27, inbuffer.pos());
+        assertEquals(27, inbuffer.limit());
+        assertEquals(0, inbuffer.length());
+
+        assertEquals(-1, inbuffer.read(tmp1));
+        assertEquals(-1, inbuffer.read(tmp1));
+        assertEquals(-1, inbuffer.read());
+        assertEquals(-1, inbuffer.read());
+    }
+
+    public void testPatternMatching1() throws Exception {
+        String text = "blabla d is the word";
+        String pattern = "d";
+        byte[] b1 = text.getBytes("US-ASCII");
+        byte[] b2 = pattern.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        int i = inbuffer.indexOf(b2);
+        assertEquals(7, i);
+    }
+    
+    public void testPatternMatching2() throws Exception {
+        String text = "disddisdissdsidsidsiid";
+        String pattern = "siid";
+        byte[] b1 = text.getBytes("US-ASCII");
+        byte[] b2 = pattern.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        int i = inbuffer.indexOf(b2);
+        assertEquals(18, i);
+    }
+    
+    public void testPatternMatching3() throws Exception {
+        String text = "bla bla yada yada haha haha";
+        String pattern = "blah";
+        byte[] b1 = text.getBytes("US-ASCII");
+        byte[] b2 = pattern.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        int i = inbuffer.indexOf(b2);
+        assertEquals(-1, i);
+    }
+    
+    public void testPatternMatching4() throws Exception {
+        String text = "bla bla yada yada haha haha";
+        String pattern = "bla";
+        byte[] b1 = text.getBytes("US-ASCII");
+        byte[] b2 = pattern.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        int i = inbuffer.indexOf(b2);
+        assertEquals(0, i);
+    }
+
+    public void testPatternOutOfBound() throws Exception {
+        String text = "bla bla yada yada haha haha";
+        String pattern1 = "bla bla";
+        byte[] b1 = text.getBytes("US-ASCII");
+        byte[] b2 = pattern1.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        byte[] tmp = new byte[3];
+        inbuffer.read(tmp);
+        int i = inbuffer.indexOf(b2, inbuffer.pos(), inbuffer.length());
+        assertEquals(-1, i);
+        i = inbuffer.indexOf(b2, inbuffer.pos(), inbuffer.length() - 1);
+        assertEquals(-1, i);
+    }
+
+    public void testCharOutOfBound() throws Exception {
+        String text = "zzz blah blah blah ggg";
+        byte[] b1 = text.getBytes("US-ASCII");
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        byte[] tmp = new byte[3];
+        inbuffer.read(tmp);
+        int i = inbuffer.indexOf((byte)'z', inbuffer.pos(), inbuffer.length());
+        assertEquals(-1, i);
+        i = inbuffer.indexOf((byte)'g', inbuffer.pos(), inbuffer.length() - 3);
+        assertEquals(-1, i);
+    }
+    
+    public void test0xFFInBinaryStream() throws Exception {
+        byte[] b1 = new byte[] {1, 2, 3, (byte) 0xff, 10, 1, 2, 3};
+        byte[] b2 = new byte[] {10};
+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        inbuffer.fillBuffer();
+        int i = inbuffer.indexOf(b2);
+        assertEquals(4, i);
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamTest.java
new file mode 100644
index 0000000..7f4b5e3
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/BufferedLineReaderInputStreamTest.java
@@ -0,0 +1,166 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
+import org.apache.james.mime4j.io.LineReaderInputStream;
+import org.apache.james.mime4j.io.MaxLineLimitException;
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+public class BufferedLineReaderInputStreamTest extends TestCase {
+
+    public void testBasicOperations() throws Exception {
+        String text = "ah blahblah";
+        byte[] b1 = text.getBytes("US-ASCII");
+        BufferedLineReaderInputStream instream = new BufferedLineReaderInputStream(new ByteArrayInputStream(b1), 4096);
+        
+        assertEquals((byte)'a', instream.read());
+        assertEquals((byte)'h', instream.read());
+        assertEquals((byte)' ', instream.read());
+
+        byte[] tmp1 = new byte[4];
+        assertEquals(4, instream.read(tmp1));
+        assertEquals(4, instream.read(tmp1));
+
+        assertEquals(-1, instream.read(tmp1));
+        assertEquals(-1, instream.read(tmp1));
+        assertEquals(-1, instream.read());
+        assertEquals(-1, instream.read());
+    }
+
+    public void testBasicReadLine() throws Exception {
+        
+        String[] teststrs = new String[5];
+        teststrs[0] = "Hello\r\n";
+        teststrs[1] = "This string should be much longer than the size of the input buffer " +
+                "which is only 16 bytes for this test\r\n";
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 15; i++) {
+            sb.append("123456789 ");
+        }
+        sb.append("and stuff like that\r\n");
+        teststrs[2] = sb.toString();
+        teststrs[3] = "\r\n";
+        teststrs[4] = "And goodbye\r\n";
+
+        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
+        
+        for (String teststr : teststrs) {
+            outstream.write(teststr.getBytes("US-ASCII"));
+        }
+        byte[] raw = outstream.toByteArray();
+        
+        BufferedLineReaderInputStream instream = new BufferedLineReaderInputStream(new ByteArrayInputStream(raw), 16); 
+        
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        for (String teststr : teststrs) {
+            linebuf.clear();
+            instream.readLine(linebuf);
+            String s = new String(linebuf.toByteArray(), "US-ASCII");
+            assertEquals(teststr, s);
+        }
+        assertEquals(-1, instream.readLine(linebuf));
+        assertEquals(-1, instream.readLine(linebuf));
+    }
+    
+    public void testReadEmptyLine() throws Exception {
+        
+        String teststr = "\n\n\r\n\r\r\n\n\n\n\n\n";
+        byte[] raw = teststr.getBytes("US-ASCII");
+        
+        LineReaderInputStream instream = new BufferedLineReaderInputStream(new ByteArrayInputStream(raw), 4); 
+        
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        linebuf.clear();
+        instream.readLine(linebuf);
+        String s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+        
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+        
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\r\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\r\r\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        assertEquals(-1, instream.readLine(linebuf));
+        assertEquals(-1, instream.readLine(linebuf));
+    }
+
+    public void testReadEmptyLineMaxLimit() throws Exception {
+        
+        String teststr = "1234567890\r\n";
+        byte[] raw = teststr.getBytes("US-ASCII");
+        
+        LineReaderInputStream instream1 = new BufferedLineReaderInputStream(
+                new ByteArrayInputStream(raw), 1024, 13); 
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        linebuf.clear();
+        instream1.readLine(linebuf);
+
+        LineReaderInputStream instream2 = new BufferedLineReaderInputStream(
+                new ByteArrayInputStream(raw), 1024, 12); 
+        linebuf.clear();
+        try {
+            instream2.readLine(linebuf);
+            fail("MaxLineLimitException should have been thrown");
+        } catch (MaxLineLimitException ex) {
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/EOLConvertingInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/EOLConvertingInputStreamTest.java
new file mode 100644
index 0000000..05413c0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/EOLConvertingInputStreamTest.java
@@ -0,0 +1,120 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import java.io.ByteArrayInputStream;

+import java.io.IOException;

+import java.io.UnsupportedEncodingException;

+

+import org.apache.james.mime4j.io.EOLConvertingInputStream;

+

+

+import junit.framework.TestCase;

+

+public class EOLConvertingInputStreamTest extends TestCase {

+

+    public void testRead() throws IOException {

+        testConvertBoth("Line 1\r\nLine 2\r\n", "Line 1\r\nLine 2\r\n");

+        testConvertCR("Line 1\r\nLine 2\r\n", "Line 1\r\nLine 2\r\n");

+        testConvertLF("Line 1\r\nLine 2\r\n", "Line 1\r\nLine 2\r\n");

+        

+        testConvertBoth("Line 1\n\rLine 2\n\r", "Line 1\r\n\r\nLine 2\r\n\r\n");

+        testConvertCR("Line 1\n\rLine 2\n\r", "Line 1\n\r\nLine 2\n\r\n");

+        testConvertLF("Line 1\n\rLine 2\n\r", "Line 1\r\n\rLine 2\r\n\r");

+        

+        testConvertBoth("Line 1\nLine 2\n", "Line 1\r\nLine 2\r\n");

+        testConvertCR("Line 1\nLine 2\n", "Line 1\nLine 2\n");

+        testConvertLF("Line 1\nLine 2\n", "Line 1\r\nLine 2\r\n");

+        

+        testConvertBoth("Line 1\rLine 2\r", "Line 1\r\nLine 2\r\n");

+        testConvertCR("Line 1\rLine 2\r", "Line 1\r\nLine 2\r\n");

+        testConvertLF("Line 1\rLine 2\r", "Line 1\rLine 2\r");

+        

+        testConvertBoth("\r\n", "\r\n");

+        testConvertCR("\r\n", "\r\n");

+        testConvertLF("\r\n", "\r\n");

+        

+        testConvertBoth("\n", "\r\n");

+        testConvertCR("\n", "\n");

+        testConvertLF("\n", "\r\n");

+        

+        testConvertBoth("\r", "\r\n");

+        testConvertCR("\r", "\r\n");

+        testConvertLF("\r", "\r");

+        

+        testConvertBoth("", "");

+        testConvertCR("", "");

+        testConvertLF("", "");

+    }

+

+    private void testConvertBoth(String s1, String s2) throws IOException {

+        byte[] bytes = new byte[1024];

+        

+        ByteArrayInputStream bais = new ByteArrayInputStream(fromString(s1));

+        EOLConvertingInputStream in = 

+            new EOLConvertingInputStream(bais, 

+                        EOLConvertingInputStream.CONVERT_BOTH);

+        int n = in.read(bytes);

+        assertEquals(s2, toString(bytes, n));

+    }

+    

+    private void testConvertCR(String s1, String s2) throws IOException {

+        byte[] bytes = new byte[1024];

+        

+        ByteArrayInputStream bais = new ByteArrayInputStream(fromString(s1));

+        EOLConvertingInputStream in = 

+            new EOLConvertingInputStream(bais, 

+                        EOLConvertingInputStream.CONVERT_CR);

+        int n = in.read(bytes);

+        assertEquals(s2, toString(bytes, n));

+    }

+    

+    private void testConvertLF(String s1, String s2) throws IOException {

+        byte[] bytes = new byte[1024];

+        

+        ByteArrayInputStream bais = new ByteArrayInputStream(fromString(s1));

+        EOLConvertingInputStream in = 

+            new EOLConvertingInputStream(bais, 

+                        EOLConvertingInputStream.CONVERT_LF);

+        int n = in.read(bytes);

+        assertEquals(s2, toString(bytes, n));

+    }

+    

+    private String toString(byte[] b, int len) {

+        try {

+            if (len == -1) {

+                return "";

+            }

+            return new String(b, 0, len, "US-ASCII");

+        } catch (UnsupportedEncodingException e) {

+            fail(e.getMessage());

+            return null;

+        }

+    }    

+    

+    private byte[] fromString(String s) {

+        try {

+            return s.getBytes("US-ASCII");

+        } catch (UnsupportedEncodingException e) {

+            fail(e.getMessage());

+            return null;

+        }

+    }    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java
new file mode 100644
index 0000000..6a79822
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LimitedInputStreamTest.java
@@ -0,0 +1,56 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class LimitedInputStreamTest extends TestCase {
+
+    public void testUpToLimitRead() throws IOException {
+        byte[] data = new byte[] {'0', '1', '2', '3', '4', '5', '6'};
+        ByteArrayInputStream instream = new ByteArrayInputStream(data);
+        LimitedInputStream limitedStream = new LimitedInputStream(instream, 3);
+        assertEquals(0, limitedStream.getPosition());
+        assertTrue(limitedStream.read() != -1);
+        assertEquals(1, limitedStream.getPosition());
+        byte[] tmp = new byte[3];
+        assertEquals(2, limitedStream.read(tmp));
+        assertEquals(3, limitedStream.getPosition());
+        try {
+            limitedStream.read();
+            fail("IOException should have been thrown");
+        } catch (IOException ex) {
+        }
+        try {
+            limitedStream.read(tmp);
+            fail("IOException should have been thrown");
+        } catch (IOException ex) {
+        }
+        try {
+            limitedStream.skip(2);
+            fail("IOException should have been thrown");
+        } catch (IOException ex) {
+        }
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LineNumberInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LineNumberInputStreamTest.java
new file mode 100755
index 0000000..bfefcda
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LineNumberInputStreamTest.java
@@ -0,0 +1,81 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import java.io.ByteArrayInputStream;

+import java.io.IOException;

+

+import org.apache.james.mime4j.io.LineNumberInputStream;

+

+import junit.framework.TestCase;

+

+public class LineNumberInputStreamTest extends TestCase {

+    /**

+     * Tests that reading single bytes updates the line number appropriately.

+     */

+    public void testReadSingleByte() throws IOException {

+        String s = "Yada\r\nyada\r\nyada\r\n";

+        LineNumberInputStream is = new LineNumberInputStream(

+                new ByteArrayInputStream(s.getBytes()));

+

+        for (int i = 0; i < 6; i++) {

+            assertEquals(1, is.getLineNumber());

+            is.read();

+        }

+

+        for (int i = 6; i < 12; i++) {

+            assertEquals(2, is.getLineNumber());

+            is.read();

+        }

+

+        for (int i = 12; i < 18; i++) {

+            assertEquals(3, is.getLineNumber());

+            is.read();

+        }

+

+        assertEquals(4, is.getLineNumber());

+        assertEquals(-1, is.read());

+    }

+

+    /**

+     * Tests that reading multiple bytes at once updates the line number

+     * appropriately.

+     */

+    public void testReadManyBytes() throws IOException {

+        String s = "Yada\r\nyada\r\nyada\r\n";

+        LineNumberInputStream is = new LineNumberInputStream(

+                new ByteArrayInputStream(s.getBytes()));

+

+        byte[] buf = new byte[4];

+        assertEquals(1, is.getLineNumber());

+        is.read(buf);

+        assertEquals(1, is.getLineNumber());

+        is.read(buf);

+        assertEquals(2, is.getLineNumber());

+        is.read(buf);

+        assertEquals(3, is.getLineNumber());

+        is.read(buf);

+        assertEquals(3, is.getLineNumber());

+        is.read(buf);

+        assertEquals(4, is.getLineNumber());

+

+        assertEquals(-1, is.read());

+    }

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LineReaderInputStreamAdaptorTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LineReaderInputStreamAdaptorTest.java
new file mode 100644
index 0000000..518cc08
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/LineReaderInputStreamAdaptorTest.java
@@ -0,0 +1,169 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import org.apache.james.mime4j.io.LineReaderInputStreamAdaptor;
+import org.apache.james.mime4j.io.MaxLineLimitException;
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+public class LineReaderInputStreamAdaptorTest extends TestCase {
+
+    public void testBasicOperations() throws Exception {
+        String text = "ah blahblah";
+        byte[] b1 = text.getBytes("US-ASCII");
+        
+        LineReaderInputStreamAdaptor instream = new LineReaderInputStreamAdaptor(
+                new ByteArrayInputStream(b1)); 
+        
+        assertEquals((byte)'a', instream.read());
+        assertEquals((byte)'h', instream.read());
+        assertEquals((byte)' ', instream.read());
+
+        byte[] tmp1 = new byte[4];
+        assertEquals(4, instream.read(tmp1));
+        assertEquals(4, instream.read(tmp1));
+
+        assertEquals(-1, instream.read(tmp1));
+        assertEquals(-1, instream.read(tmp1));
+        assertEquals(-1, instream.read());
+        assertEquals(-1, instream.read());
+    }
+
+    public void testBasicReadLine() throws Exception {
+        
+        String[] teststrs = new String[5];
+        teststrs[0] = "Hello\r\n";
+        teststrs[1] = "This string should be much longer than the size of the input buffer " +
+                "which is only 16 bytes for this test\r\n";
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 15; i++) {
+            sb.append("123456789 ");
+        }
+        sb.append("and stuff like that\r\n");
+        teststrs[2] = sb.toString();
+        teststrs[3] = "\r\n";
+        teststrs[4] = "And goodbye\r\n";
+
+        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
+        
+        for (String teststr : teststrs) {
+            outstream.write(teststr.getBytes("US-ASCII"));
+        }
+        byte[] raw = outstream.toByteArray();
+        
+        LineReaderInputStreamAdaptor instream = new LineReaderInputStreamAdaptor(
+                new ByteArrayInputStream(raw)); 
+        
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        for (String teststr : teststrs) {
+            linebuf.clear();
+            instream.readLine(linebuf);
+            String s = new String(linebuf.toByteArray(), "US-ASCII");
+            assertEquals(teststr, s);
+        }
+        assertEquals(-1, instream.readLine(linebuf));
+        assertEquals(-1, instream.readLine(linebuf));
+    }
+    
+    public void testReadEmptyLine() throws Exception {
+        
+        String teststr = "\n\n\r\n\r\r\n\n\n\n\n\n";
+        byte[] raw = teststr.getBytes("US-ASCII");
+        
+        LineReaderInputStreamAdaptor instream = new LineReaderInputStreamAdaptor(
+                new ByteArrayInputStream(raw)); 
+        
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        linebuf.clear();
+        instream.readLine(linebuf);
+        String s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+        
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+        
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\r\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\r\r\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        linebuf.clear();
+        instream.readLine(linebuf);
+        s = new String(linebuf.toByteArray(), "US-ASCII");
+        assertEquals("\n", s);
+
+        assertEquals(-1, instream.readLine(linebuf));
+        assertEquals(-1, instream.readLine(linebuf));
+    }
+
+    public void testReadEmptyLineMaxLimit() throws Exception {
+        
+        String teststr = "1234567890\r\n";
+        byte[] raw = teststr.getBytes("US-ASCII");
+        
+        LineReaderInputStreamAdaptor instream1 = new LineReaderInputStreamAdaptor(
+                new ByteArrayInputStream(raw), 13); 
+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 
+        linebuf.clear();
+        instream1.readLine(linebuf);
+
+        LineReaderInputStreamAdaptor instream2 = new LineReaderInputStreamAdaptor(
+                new ByteArrayInputStream(raw), 12); 
+        linebuf.clear();
+        try {
+            instream2.readLine(linebuf);
+            fail("MaxLineLimitException should have been thrown");
+        } catch (MaxLineLimitException ex) {
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/MimeBoundaryInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/MimeBoundaryInputStreamTest.java
new file mode 100644
index 0000000..91d00e2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/MimeBoundaryInputStreamTest.java
@@ -0,0 +1,343 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.io;

+

+import java.io.ByteArrayInputStream;

+import java.io.ByteArrayOutputStream;

+import java.io.IOException;

+import java.io.InputStream;

+

+import org.apache.james.mime4j.io.BufferedLineReaderInputStream;

+import org.apache.james.mime4j.io.LineReaderInputStream;

+import org.apache.james.mime4j.io.MimeBoundaryInputStream;

+import org.apache.james.mime4j.util.ByteArrayBuffer;

+

+

+import junit.framework.TestCase;

+

+public class MimeBoundaryInputStreamTest extends TestCase {

+

+    public void testBasicReading() throws IOException {

+        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +

+                "Line 3\r\nLine 4\r\n--boundary--";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));

+        

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        

+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 1\r\nLine 2", read(mime1, 5));

+        

+        assertFalse(mime1.isLastPart());

+        

+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 3\r\nLine 4", read(mime2, 5));

+

+        assertTrue(mime2.isLastPart());

+    }

+    

+    public void testLenientLineDelimiterReading() throws IOException {

+        String text = "Line 1\r\nLine 2\n--boundary\n" +

+                "Line 3\r\nLine 4\n--boundary--\n";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));

+        

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        

+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 1\r\nLine 2", read(mime1, 5));

+        

+        assertFalse(mime1.isLastPart());

+        

+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 3\r\nLine 4", read(mime2, 5));

+

+        assertTrue(mime2.isLastPart());

+    }

+    

+    public void testBasicReadingSmallBuffer1() throws IOException {

+        String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +

+                "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));

+        

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 20); 

+        

+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada", 

+                read(mime1, 10));

+        

+        assertFalse(mime1.isLastPart());

+        

+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah", 

+                read(mime2, 10));

+

+        assertTrue(mime2.isLastPart());

+    }

+    

+    public void testBasicReadingSmallBuffer2() throws IOException {

+        String text = "yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada\r\n--boundary\r\n" +

+                "blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah\r\n--boundary--";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));

+        

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 20); 

+        

+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");

+        

+        assertEquals("yadayadayadayadayadayadayadayadayadayadayadayadayadayadayadayada", 

+                read(mime1, 25));

+        

+        assertFalse(mime1.isLastPart());

+        

+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("blahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblahblah", 

+                read(mime2, 25));

+

+        assertTrue(mime2.isLastPart());

+    }

+    

+    public void testBasicReadingByOneByte() throws IOException {

+        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +

+                "Line 3\r\nLine 4\r\n--boundary--";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));

+        

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        

+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 1\r\nLine 2", readByOneByte(mime1));

+        

+        assertFalse(mime1.isLastPart());

+        

+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 3\r\nLine 4", readByOneByte(mime2));

+

+        assertTrue(mime2.isLastPart());

+    }

+    

+    /**

+     * Tests that a CRLF immediately preceding a boundary isn't included in

+     * the stream.

+     */

+    public void testCRLFPrecedingBoundary() throws IOException {

+        String text = "Line 1\r\nLine 2\r\n--boundary\r\n" +

+                "Line 3\r\nLine 4\r\n\r\n--boundary\r\n";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("US-ASCII"));

+        

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        

+        MimeBoundaryInputStream mime1 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 1\r\nLine 2", read(mime1, 5));

+        

+        assertFalse(mime1.isLastPart());

+        

+        MimeBoundaryInputStream mime2 = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 3\r\nLine 4\r\n", read(mime2, 5));

+

+        assertFalse(mime2.isLastPart());

+    }

+    

+    private String readByOneByte(InputStream is) throws IOException {

+        StringBuilder sb = new StringBuilder();

+        int b = 0;

+        while ((b = is.read()) != -1) {

+            sb.append((char) b);

+        }

+        return sb.toString();

+    }

+

+    private String read(InputStream is, int bufsize) throws IOException {

+        StringBuilder sb = new StringBuilder();

+        int l;

+        byte[] tmp = new byte[bufsize];

+        while ((l = is.read(tmp)) != -1) {

+            for (int i = 0; i < l; i++) {

+                sb.append((char) tmp[i]);

+            }

+        }

+        return sb.toString();

+    }

+    

+    /**

+     * Tests that a stream containing only a boundary is empty.

+     */

+    public void testImmediateBoundary() throws IOException {

+        String text = "--boundary\r\n";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        

+        MimeBoundaryInputStream stream = 

+            new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals(-1, stream.read());

+        

+        text = "\r\n--boundary\r\n";

+        

+        bis = new ByteArrayInputStream(text.getBytes());

+        buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        stream = 

+            new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals(-1, stream.read());

+    }

+    

+    /**

+     * Tests that hasMoreParts behave as expected.

+     */

+    public void testHasMoreParts() throws IOException {

+        String text = "--boundary--\r\n";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        MimeBoundaryInputStream stream = 

+            new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals(-1, stream.read());

+        assertTrue(stream.isLastPart());

+    }

+    

+    /**

+     * Tests that a stream containing only a boundary is empty.

+     */

+    public void testPrefixIsBoundary() throws IOException {

+        String text = "Line 1\r\n\r\n--boundaryyada\r\n";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        MimeBoundaryInputStream stream = 

+            new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals("Line 1\r\n", read(stream, 100));

+        

+        text = "--boundaryyada\r\n";

+        

+        bis = new ByteArrayInputStream(text.getBytes());

+        buffer = new BufferedLineReaderInputStream(bis, 4096); 

+        stream = new MimeBoundaryInputStream(buffer, "boundary");

+        assertEquals(-1, stream.read());

+    }

+    

+    

+    public void testBasicReadLine() throws Exception {

+        

+        String[] teststrs = new String[5];

+        teststrs[0] = "Hello\r\n";

+        teststrs[1] = "This string should be much longer than the size of the input buffer " +

+                "which is only 20 bytes for this test\r\n";

+        StringBuilder sb = new StringBuilder();

+        for (int i = 0; i < 15; i++) {

+            sb.append("123456789 ");

+        }

+        sb.append("and stuff like that\r\n");

+        teststrs[2] = sb.toString();

+        teststrs[3] = "\r\n";

+        teststrs[4] = "And goodbye\r\n";

+

+        String term = "\r\n--1234\r\n";

+        

+        ByteArrayOutputStream outstream = new ByteArrayOutputStream();

+        

+        for (String teststr : teststrs) {

+            outstream.write(teststr.getBytes("US-ASCII"));

+        }

+        outstream.write(term.getBytes("US-ASCII"));

+        byte[] raw = outstream.toByteArray();

+        

+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(raw), 20); 

+        LineReaderInputStream instream = new MimeBoundaryInputStream(inbuffer, "1234"); 

+        

+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 

+        for (String teststr : teststrs) {

+            linebuf.clear();

+            instream.readLine(linebuf);

+            String s = new String(linebuf.toByteArray(), "US-ASCII");

+            assertEquals(teststr, s);

+        }

+        assertEquals(-1, instream.readLine(linebuf));

+        assertEquals(-1, instream.readLine(linebuf));

+    }

+    

+    public void testReadEmptyLine() throws Exception {

+        

+        String teststr = "01234567890123456789\n\n\r\n\r\r\n\n\n\n\n\n--1234\r\n";

+        byte[] raw = teststr.getBytes("US-ASCII");

+        

+        BufferedLineReaderInputStream inbuffer = new BufferedLineReaderInputStream(new ByteArrayInputStream(raw), 20); 

+        LineReaderInputStream instream = new MimeBoundaryInputStream(inbuffer, "1234"); 

+        

+        ByteArrayBuffer linebuf = new ByteArrayBuffer(8); 

+        linebuf.clear();

+        instream.readLine(linebuf);

+        String s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("01234567890123456789\n", s);

+        

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\n", s);

+        

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\r\n", s);

+

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\r\r\n", s);

+

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\n", s);

+

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\n", s);

+

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\n", s);

+

+        linebuf.clear();

+        instream.readLine(linebuf);

+        s = new String(linebuf.toByteArray(), "US-ASCII");

+        assertEquals("\n", s);

+

+        assertEquals(-1, instream.readLine(linebuf));

+        assertEquals(-1, instream.readLine(linebuf));

+    }

+    

+    public void testboundaryLongerThanBuffer() throws IOException {

+        String text = "--looooooooooooooooooooooooooong-boundary\r\n";

+        

+        ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes());

+        BufferedLineReaderInputStream buffer = new BufferedLineReaderInputStream(bis, 10); 

+        

+        try {

+            new MimeBoundaryInputStream(buffer, "looooooooooooooooooooooooooong-boundary");

+            fail("IllegalArgumentException should have been thrown");

+        } catch (IllegalArgumentException expected) {

+        }

+    }

+

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java
new file mode 100644
index 0000000..62c5495
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/io/PositionInputStreamTest.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class PositionInputStreamTest extends TestCase {
+
+    public void testPositionCounting() throws IOException {
+        byte[] data = new byte[] {'0', '1', '2', '3', '4', '5', '6'};
+        ByteArrayInputStream instream = new ByteArrayInputStream(data);
+        PositionInputStream countingStream = new PositionInputStream(instream);
+        assertEquals(0, countingStream.getPosition());
+        assertTrue(countingStream.read() != -1);
+        assertEquals(1, countingStream.getPosition());
+        byte[] tmp = new byte[3];
+        assertEquals(3, countingStream.read(tmp));
+        assertEquals(4, countingStream.getPosition());
+        assertEquals(2, countingStream.skip(2));
+        assertEquals(6, countingStream.getPosition());
+        assertTrue(countingStream.read() != -1);
+        assertEquals(7, countingStream.getPosition());
+        assertTrue(countingStream.read() == -1);
+        assertEquals(7, countingStream.getPosition());
+        assertTrue(countingStream.read() == -1);
+        assertEquals(7, countingStream.getPosition());
+        assertTrue(countingStream.read(tmp) == -1);
+        assertEquals(7, countingStream.getPosition());
+        assertTrue(countingStream.read(tmp) == -1);
+        assertEquals(7, countingStream.getPosition());
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/CopyConstructorTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/CopyConstructorTest.java
new file mode 100644
index 0000000..6e4a0f0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/CopyConstructorTest.java
@@ -0,0 +1,188 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.james.mime4j.field.AbstractField;
+import org.apache.james.mime4j.parser.Field;
+
+import junit.framework.TestCase;
+
+public class CopyConstructorTest extends TestCase {
+
+    public void testCopyEmptyMessage() throws Exception {
+        Message original = new Message();
+
+        Message copy = new Message(original);
+
+        assertNull(copy.getHeader());
+        assertNull(copy.getBody());
+        assertNull(copy.getParent());
+    }
+
+    public void testCopyMessage() throws Exception {
+        Message parent = new Message();
+        Header header = new Header();
+        Body body = new BodyFactory().textBody("test");
+
+        Message original = new Message();
+        original.setHeader(header);
+        original.setBody(body);
+        original.setParent(parent);
+
+        Message copy = new Message(original);
+
+        assertNotNull(copy.getHeader());
+        assertNotSame(header, copy.getHeader());
+
+        assertNotNull(copy.getBody());
+        assertNotSame(body, copy.getBody());
+
+        assertSame(copy, copy.getBody().getParent());
+
+        assertNull(copy.getParent());
+    }
+
+    public void testCopyEmptyBodyPart() throws Exception {
+        BodyPart original = new BodyPart();
+
+        BodyPart copy = new BodyPart(original);
+
+        assertNull(copy.getHeader());
+        assertNull(copy.getBody());
+        assertNull(copy.getParent());
+    }
+
+    public void testCopyBodyPart() throws Exception {
+        Message parent = new Message();
+        Header header = new Header();
+        Body body = new BodyFactory().textBody("test");
+
+        BodyPart original = new BodyPart();
+        original.setHeader(header);
+        original.setBody(body);
+        original.setParent(parent);
+
+        BodyPart copy = new BodyPart(original);
+
+        assertNotNull(copy.getHeader());
+        assertNotSame(header, copy.getHeader());
+
+        assertNotNull(copy.getBody());
+        assertNotSame(body, copy.getBody());
+
+        assertSame(copy, copy.getBody().getParent());
+
+        assertNull(copy.getParent());
+    }
+
+    public void testCopyEmptyMultipart() throws Exception {
+        Multipart original = new Multipart("mixed");
+
+        Multipart copy = new Multipart(original);
+
+        assertSame(original.getPreamble(), copy.getPreamble());
+        assertSame(original.getEpilogue(), copy.getEpilogue());
+        assertSame(original.getSubType(), copy.getSubType());
+        assertTrue(copy.getBodyParts().isEmpty());
+        assertNull(copy.getParent());
+    }
+
+    public void testCopyMultipart() throws Exception {
+        Message parent = new Message();
+        BodyPart bodyPart = new BodyPart();
+
+        Multipart original = new Multipart("mixed");
+        original.setPreamble("preamble");
+        original.setEpilogue("epilogue");
+        original.setParent(parent);
+        original.addBodyPart(bodyPart);
+
+        Multipart copy = new Multipart(original);
+
+        assertSame(original.getPreamble(), copy.getPreamble());
+        assertSame(original.getEpilogue(), copy.getEpilogue());
+        assertSame(original.getSubType(), copy.getSubType());
+        assertEquals(1, copy.getBodyParts().size());
+        assertNull(copy.getParent());
+
+        BodyPart bodyPartCopy = copy.getBodyParts().iterator().next();
+        assertNotSame(bodyPart, bodyPartCopy);
+
+        assertSame(parent, bodyPart.getParent());
+        assertNull(bodyPartCopy.getParent());
+    }
+
+    public void testCopyMultipartMessage() throws Exception {
+        BodyPart bodyPart1 = new BodyPart();
+        BodyPart bodyPart2 = new BodyPart();
+
+        Multipart multipart = new Multipart("mixed");
+        multipart.addBodyPart(bodyPart1);
+        multipart.addBodyPart(bodyPart2);
+
+        Message original = new Message();
+        original.setHeader(new Header());
+        original.setBody(multipart);
+
+        Message copy = new Message(original);
+
+        Multipart multipartCopy = (Multipart) copy.getBody();
+        List<BodyPart> bodyParts = multipartCopy.getBodyParts();
+        BodyPart bodyPartCopy1 = bodyParts.get(0);
+        BodyPart bodyPartCopy2 = bodyParts.get(1);
+
+        assertNotSame(bodyPart1, bodyPartCopy1);
+        assertEquals(original, bodyPart1.getParent());
+        assertEquals(copy, bodyPartCopy1.getParent());
+
+        assertNotSame(bodyPart2, bodyPartCopy2);
+        assertEquals(original, bodyPart2.getParent());
+        assertEquals(copy, bodyPartCopy2.getParent());
+    }
+
+    public void testCopyHeader() throws Exception {
+        Field f1 = AbstractField.parse("name1: value1");
+        Field f2 = AbstractField.parse("name2: value");
+        Field f3 = AbstractField.parse("name1: value2");
+
+        Header original = new Header();
+        original.addField(f1);
+        original.addField(f2);
+        original.addField(f3);
+
+        Header copy = new Header(original);
+
+        // copy must have same fields as original
+        assertEquals(Arrays.asList(f1, f2, f3), copy.getFields());
+        assertEquals(Arrays.asList(f1, f3), copy.getFields("name1"));
+
+        // modify original
+        original.removeFields("name1");
+        assertEquals(Arrays.asList(f2), original.getFields());
+
+        // copy may not be affected
+        assertEquals(Arrays.asList(f1, f2, f3), copy.getFields());
+        assertEquals(Arrays.asList(f1, f3), copy.getFields("name1"));
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/EntityTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/EntityTest.java
new file mode 100644
index 0000000..974167e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/EntityTest.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import org.apache.james.mime4j.field.AbstractField;
+import org.apache.james.mime4j.message.Entity;
+
+import junit.framework.TestCase;
+
+public class EntityTest extends TestCase {
+
+    public void testSetBody() throws Exception {
+        Entity entity = new BodyPart();
+        assertNull(entity.getBody());
+
+        Body body = new BodyFactory().textBody("test");
+        assertNull(body.getParent());
+
+        entity.setBody(body);
+        assertSame(body, entity.getBody());
+        assertSame(entity, body.getParent());
+    }
+
+    public void testSetBodyTwice() throws Exception {
+        Entity entity = new BodyPart();
+
+        Body b1 = new BodyFactory().textBody("foo");
+        Body b2 = new BodyFactory().textBody("bar");
+
+        entity.setBody(b1);
+        try {
+            entity.setBody(b2);
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    public void testRemoveBody() throws Exception {
+        Entity entity = new BodyPart();
+        Body body = new BodyFactory().textBody("test");
+        entity.setBody(body);
+
+        Body removed = entity.removeBody();
+        assertSame(body, removed);
+
+        assertNull(entity.getBody());
+        assertNull(removed.getParent());
+    }
+
+    public void testGetDispositionType() throws Exception {
+        Entity entity = new BodyPart();
+
+        assertNull(entity.getDispositionType());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Content-Disposition: inline"));
+        entity.setHeader(header);
+
+        assertEquals("inline", entity.getDispositionType());
+    }
+
+    public void testSetContentDispositionType() throws Exception {
+        Entity entity = new BodyPart();
+
+        entity.setContentDisposition("attachment");
+
+        assertEquals("attachment", entity.getHeader().getField(
+                "Content-Disposition").getBody());
+    }
+
+    public void testSetContentDispositionTypeFilename() throws Exception {
+        Entity entity = new BodyPart();
+
+        entity.setContentDisposition("attachment", "some file.dat");
+
+        assertEquals("attachment; filename=\"some file.dat\"", entity
+                .getHeader().getField("Content-Disposition").getBody());
+    }
+
+    public void testGetFilename() throws Exception {
+        Entity entity = new BodyPart();
+
+        assertNull(entity.getFilename());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Content-Disposition: attachment; "
+                + "filename=\"some file.dat\""));
+        entity.setHeader(header);
+
+        assertEquals("some file.dat", entity.getFilename());
+    }
+
+    public void testSetFilename() throws Exception {
+        Entity entity = new BodyPart();
+
+        entity.setFilename("file name.ext");
+
+        assertEquals("attachment; filename=\"file name.ext\"", entity
+                .getHeader().getField("Content-Disposition").getBody());
+
+        entity.setFilename(null);
+
+        assertEquals("attachment", entity.getHeader().getField(
+                "Content-Disposition").getBody());
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java
new file mode 100644
index 0000000..30b4f1b
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java
@@ -0,0 +1,111 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+import org.apache.james.mime4j.parser.MimeEntityConfig;
+import org.apache.log4j.BasicConfigurator;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Creates a TestSuite running the test for each .msg file in the test resouce folder.
+ * Allow running of a single test from Unit testing GUIs
+ */
+public class ExampleMessagesRoundtripTest extends TestCase {
+
+    private File file;
+
+
+    public ExampleMessagesRoundtripTest(String testName) {
+        this(testName, ExampleMessagesRountripTestSuite.getFile(testName));
+    }
+
+    public ExampleMessagesRoundtripTest(String name, File testFile) {
+        super(name);
+        this.file = testFile;
+    }
+
+    @Override
+    public void setUp() {
+        BasicConfigurator.resetConfiguration();
+        BasicConfigurator.configure();
+    }
+   
+    @Override
+    protected void runTest() throws Throwable {
+        MimeEntityConfig config = new MimeEntityConfig();
+        config.setMaxLineLen(-1);
+        Message inputMessage = new Message(new FileInputStream(file), config);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        inputMessage.writeTo(out);
+        
+        String msgoutFile = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + ".out";
+        String msgoutFileMime4j = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + ".mime4j.out";
+        
+        try {
+            ByteArrayOutputStream expectedstream = new ByteArrayOutputStream();
+            CodecUtil.copy(new FileInputStream(msgoutFile), expectedstream);
+            assertEquals("Wrong Expected result", new String(expectedstream.toByteArray()), new String(out.toByteArray()));
+        } catch (FileNotFoundException e) {
+            FileOutputStream fos = new FileOutputStream(msgoutFileMime4j);
+            fos.write(out.toByteArray());
+            fos.flush();
+            fos.close();
+            fail("Expected file not found: generated a file with the expected result!");
+        }
+    }
+
+    public static Test suite() throws IOException {
+        return new ExampleMessagesRountripTestSuite();
+    }
+
+    
+    static class ExampleMessagesRountripTestSuite extends TestSuite {
+
+        private static final File TESTS_FOLDER = new File("src/test/resources/testmsgs");
+
+        public ExampleMessagesRountripTestSuite() throws IOException {
+            super();
+            File dir = TESTS_FOLDER;
+            File[] files = dir.listFiles();
+            
+            for (File f : files) {
+                if (f.getName().toLowerCase().endsWith(".msg")) {
+                    addTest(new ExampleMessagesRoundtripTest(f.getName().substring(0, f.getName().length()-4), f));
+                }
+            }
+        }
+        
+        public static File getFile(String name) {
+            return new File(TESTS_FOLDER.getAbsolutePath()+File.separator+name+".msg");
+        }
+
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/HeaderTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
new file mode 100644
index 0000000..0002707
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
@@ -0,0 +1,129 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.message;

+

+import junit.framework.TestCase;

+

+import org.apache.commons.io.output.ByteArrayOutputStream;

+import org.apache.james.mime4j.field.AbstractField;

+import org.apache.james.mime4j.parser.Field;

+import org.apache.james.mime4j.util.CharsetUtil;

+

+public class HeaderTest extends TestCase {

+

+    public static final String SUBJECT = "Subject: test";

+

+    public static final String TO = "To: anyuser <any@user>";

+

+    public void testHeader() throws Exception {

+        Header header = new Header();

+        header.addField(AbstractField.parse(SUBJECT));

+        header.addField(AbstractField.parse(TO));

+

+        assertNotNull("Subject found", header.getField("Subject"));

+        assertNotNull("To found", header.getField("To"));

+

+        assertEquals("Headers equals", SUBJECT + "\r\n" + TO + "\r\n", header

+                .toString());

+    }

+    

+    private static final String SWISS_GERMAN_HELLO = "Gr\374ezi_z\344m\344";

+

+    public void testWriteSpecialCharacters() throws Exception {

+        String hello = SWISS_GERMAN_HELLO;

+        Header header = new Header();

+        header.addField(AbstractField.parse("Hello: " + hello));

+        

+        Field field = header.getField("Hello");

+        assertNotNull(field);

+        assertEquals(hello, field.getBody());

+        

+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();

+        

+        MessageWriter.DEFAULT.writeHeader(header, buffer);

+        String s = buffer.toString(CharsetUtil.US_ASCII.name());

+        

+        assertEquals("Hello: Gr?ezi_z?m?\r\n\r\n", s);

+    }

+

+    public void testRemoveFields() throws Exception {

+        Header header = new Header();

+        header.addField(AbstractField.parse("Received: from foo by bar for james"));

+        header.addField(AbstractField.parse("Content-type: text/plain; charset=US-ASCII"));

+        header.addField(AbstractField.parse("ReCeIvEd: from bar by foo for james"));

+

+        assertEquals(3, header.getFields().size());

+        assertEquals(2, header.getFields("received").size());

+        assertEquals(1, header.getFields("Content-Type").size());

+

+        assertEquals(2, header.removeFields("rEcEiVeD"));

+

+        assertEquals(1, header.getFields().size());

+        assertEquals(0, header.getFields("received").size());

+        assertEquals(1, header.getFields("Content-Type").size());

+

+        assertEquals("Content-type", header.getFields().get(0).getName());

+    }

+

+    public void testRemoveNonExistantField() throws Exception {

+        Header header = new Header();

+        header.addField(AbstractField.parse("Received: from foo by bar for james"));

+        header.addField(AbstractField.parse("Content-type: text/plain; charset=US-ASCII"));

+        header.addField(AbstractField.parse("ReCeIvEd: from bar by foo for james"));

+

+        assertEquals(0, header.removeFields("noSuchField"));

+

+        assertEquals(3, header.getFields().size());

+        assertEquals(2, header.getFields("received").size());

+        assertEquals(1, header.getFields("Content-Type").size());

+    }

+

+    public void testSetField() throws Exception {

+        Header header = new Header();

+        header.addField(AbstractField.parse("From: mime4j@james.apache.org"));

+        header.addField(AbstractField.parse("Received: from foo by bar for james"));

+        header.addField(AbstractField.parse("Content-type: text/plain; charset=US-ASCII"));

+        header.addField(AbstractField.parse("ReCeIvEd: from bar by foo for james"));

+

+        header.setField(AbstractField.parse("received: from nobody by noone for james"));

+

+        assertEquals(3, header.getFields().size());

+        assertEquals(1, header.getFields("received").size());

+

+        assertEquals("From", header.getFields().get(0).getName());

+        assertEquals("received", header.getFields().get(1).getName());

+        assertEquals("Content-type", header.getFields().get(2).getName());

+    }

+

+    public void testSetNonExistantField() throws Exception {

+        Header header = new Header();

+        header.addField(AbstractField.parse("Received: from foo by bar for james"));

+        header.addField(AbstractField.parse("Content-type: text/plain; charset=US-ASCII"));

+        header.addField(AbstractField.parse("ReCeIvEd: from bar by foo for james"));

+

+        header.setField(AbstractField.parse("Message-ID: <msg9901@apache.org>"));

+

+        assertEquals(4, header.getFields().size());

+        assertEquals(1, header.getFields("message-id").size());

+

+        assertEquals("Message-ID", header.getFields().get(3).getName());

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageCompleteMailTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageCompleteMailTest.java
new file mode 100644
index 0000000..bc1eefa
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageCompleteMailTest.java
@@ -0,0 +1,59 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.ExampleMail;
+
+public class MessageCompleteMailTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testMultipartAlternative() throws Exception {
+        Message message = createMessage(ExampleMail.MIME_MULTIPART_ALTERNATIVE_BYTES);
+        assertTrue("Should be a multipart/alternative mail", message.isMultipart());
+        Multipart part = (Multipart)message.getBody();
+        assertEquals("alternative", part.getSubType());
+    }    
+    
+    public void testMultipartMixed() throws Exception {
+        Message message = createMessage(ExampleMail.MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BYTES);
+        assertTrue("Should be a multipart/mixed mail", message.isMultipart());
+        Multipart part = (Multipart)message.getBody();
+        assertEquals("mixed", part.getSubType());
+    }
+
+    private Message createMessage(byte[] octets) throws Exception {
+        ByteArrayInputStream in = new ByteArrayInputStream(octets);
+        Message message = new Message(in);
+        return message;
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java
new file mode 100644
index 0000000..70ff050
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageParserTest.java
@@ -0,0 +1,256 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.parser.MimeEntityConfig;
+import org.apache.james.mime4j.util.ContentUtil;
+import org.apache.james.mime4j.util.CharsetUtil;
+import org.apache.log4j.BasicConfigurator;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class MessageParserTest extends TestCase {
+    private File file = null;
+
+    public MessageParserTest(String name) {
+        this(name, MessageParserTestSuite.getFile(name));
+    }
+
+    public MessageParserTest(String name, File file) {
+        super(name);
+        this.file = file;
+    }
+
+    @Override
+    public void setUp() {
+        BasicConfigurator.resetConfiguration();
+        BasicConfigurator.configure();
+    }
+        
+    public static Test suite() {
+        return new MessageParserTestSuite();
+    }
+    
+    static class MessageParserTestSuite extends TestSuite {
+        
+        private static final File TESTS_FOLDER = new File("src/test/resources/testmsgs");
+
+        public MessageParserTestSuite() {
+            File dir = TESTS_FOLDER;
+            File[] files = dir.listFiles();
+            
+            for (int i = 0; i < files.length && i < 5000; i++) {
+                File f = files[i];
+                if (f.getName().toLowerCase().endsWith(".msg")) {
+                    addTest(new MessageParserTest(f.getName().substring(0, f.getName().length()-4), f));
+                }
+            }
+        }
+        
+        public static File getFile(String name) {
+            return new File(TESTS_FOLDER.getAbsolutePath()+File.separator+name+".msg");
+        }
+    }
+    
+    @Override
+    protected void runTest() throws IOException {
+        File f = file;
+        String fileName = file.getAbsolutePath();
+        
+        System.out.println("Parsing " + f.getName());
+        
+        MimeEntityConfig config = new MimeEntityConfig();
+        config.setMaxLineLen(-1);
+        Message m = new Message(new FileInputStream(f), config);
+        
+        String prefix = f.getName().substring(0, f.getName().length() - 4);
+        String xmlFileName = fileName.substring(0, fileName.length() - 4) 
+                                    + "_decoded.xml";
+        
+        String result = getStructure(m, prefix, "1");
+        String mime4jFileName = fileName.substring(0, fileName.length() - 4) 
+                                    + "_decoded.mime4j.xml";
+        String expected = null;
+        try {
+            expected = IOUtils.toString(new FileInputStream(xmlFileName), "ISO8859-1");
+        } catch (FileNotFoundException ex) {
+            writeToFile(result, mime4jFileName);
+            fail("Test file not found. Generated the expected result with mime4j prefix: "+ex.getMessage());
+        }
+        try {
+            assertEquals(expected, result);
+        } catch (AssertionError ae) {
+            writeToFile(result, mime4jFileName);
+            throw ae;
+        }
+    }
+
+    private void writeToFile(String result, String mime4jFileName)
+            throws FileNotFoundException, IOException,
+            UnsupportedEncodingException {
+        FileOutputStream out = new FileOutputStream(mime4jFileName);
+        out.write(result.getBytes("ISO8859-1"));
+        out.close();
+    }
+    
+    private String escape(String s) {
+        s = s.replaceAll("&", "&amp;");
+        s = s.replaceAll("<", "&lt;");
+        return s.replaceAll(">", "&gt;");
+    }
+
+    private String getStructure(Entity e, String prefix, String id) 
+            throws IOException {
+        
+        StringBuilder sb = new StringBuilder();
+        
+        if (e instanceof Message) {
+            sb.append("<message>\r\n");
+        } else {
+            sb.append("<body-part>\r\n");
+        }            
+        
+        sb.append("<header>\r\n");
+        for (Field field : e.getHeader().getFields()) {
+            sb.append("<field>\r\n"
+                    + escape(ContentUtil.decode(field.getRaw()))
+                    + "</field>\r\n");
+        }
+        sb.append("</header>\r\n");
+        
+        if (e.getBody() instanceof Multipart) {
+            sb.append("<multipart>\r\n");
+            
+            Multipart multipart =(Multipart) e.getBody(); 
+            List<BodyPart> parts = multipart.getBodyParts();
+
+            sb.append("<preamble>\r\n");
+            sb.append(escape(multipart.getPreamble()));
+            sb.append("</preamble>\r\n");
+            
+            int i = 1;
+            for (BodyPart bodyPart : parts) {
+                sb.append(getStructure(bodyPart, prefix, id + "_" + (i++)));
+            }
+
+            sb.append("<epilogue>\r\n");
+            sb.append(escape(multipart.getEpilogue()));
+            sb.append("</epilogue>\r\n");
+            
+            sb.append("</multipart>\r\n");
+            
+        } else if (e.getBody() instanceof Message) {
+            sb.append(getStructure((Message) e.getBody(), prefix, id + "_1"));
+        } else {
+            Body b = e.getBody();
+            String name = prefix + "_decoded_" + id 
+                            + (b instanceof TextBody ? ".txt" : ".bin");
+            String tag = b instanceof TextBody ? "text-body" : "binary-body";
+            sb.append("<" + tag + " name=\"" + name + "\"/>\r\n");
+                
+            File expectedFile = new File(file.getParent(), name);
+            File mime4jFile = new File(file.getParent(), 
+                              name.substring(0, name.length() - 4) + ".mime4j"
+                               + (b instanceof TextBody ? ".txt" : ".bin"));
+                
+            InputStream expected = null;
+            try {
+                expected = new BufferedInputStream(new FileInputStream(expectedFile));
+            } catch (FileNotFoundException ex) {
+                writeToFile(b, mime4jFile);
+                fail("Test file not found. Generated the expected result with mime4j prefix: "+ex.getMessage());
+            }
+            
+            try {
+                if (b instanceof TextBody) {
+                    String charset = CharsetUtil.toJavaCharset(e.getCharset());
+                    if (charset == null) {
+                        charset = "ISO8859-1";
+                    }
+
+                    String s1 = IOUtils.toString(expected, charset);
+                    String s2 = IOUtils.toString(((TextBody) b).getReader());
+                    assertEquals(expectedFile.getName(), s1, s2);
+                } else {
+                    assertEqualsBinary(expectedFile.getName(), expected,
+                            ((BinaryBody) b).getInputStream());
+                }
+            } catch (AssertionError er) {
+                writeToFile(b, mime4jFile);
+                throw er;
+            }
+        }
+        
+        
+        if (e instanceof Message) {
+            sb.append("</message>\r\n");
+        } else {
+            sb.append("</body-part>\r\n");
+        }            
+        
+        return sb.toString();
+    }
+
+    private void writeToFile(Body b, File mime4jFile)
+            throws FileNotFoundException, IOException {
+        if (b instanceof TextBody) {
+            String charset = CharsetUtil.toJavaCharset(b.getParent().getCharset());
+            if (charset == null) {
+                charset = "ISO8859-1";
+            }
+
+            OutputStream out = new FileOutputStream(mime4jFile);
+            IOUtils.copy(((TextBody) b).getReader(), out, charset);
+        } else {
+            OutputStream out = new FileOutputStream(mime4jFile);
+            IOUtils.copy(((BinaryBody) b).getInputStream(), out);
+        }
+    }
+
+    private void assertEqualsBinary(String msg, InputStream a, InputStream b) 
+            throws IOException {
+        
+        int pos = 0;
+        while (true) {
+            int b1 = a.read();
+            int b2 = b.read();
+            assertEquals(msg + " (Position " + (++pos) + ")", b1, b2);
+            
+            if (b1 == -1 || b2 == -1) {
+                break;
+            }
+        }
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageTest.java
new file mode 100644
index 0000000..1ecbf2e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageTest.java
@@ -0,0 +1,504 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.field.AbstractField;
+import org.apache.james.mime4j.field.address.Group;
+import org.apache.james.mime4j.field.address.Mailbox;
+
+public class MessageTest extends TestCase {
+    private Header headerTextPlain = null;
+    private Header headerMessageRFC822 = null;
+    private Header headerEmpty = null;
+    private Header headerMultipartMixed = null;
+    private Header headerMultipartDigest = null;
+
+    @Override
+    public void setUp() throws Exception {
+        headerTextPlain = new Header();
+        headerMessageRFC822 = new Header();
+        headerEmpty = new Header();
+        headerMultipartMixed = new Header();
+        headerMultipartDigest = new Header();
+        
+        headerTextPlain.addField(
+                AbstractField.parse("Content-Type: text/plain"));
+        headerMessageRFC822.addField(
+                AbstractField.parse("Content-Type: message/RFC822"));
+        headerMultipartMixed.addField(
+                AbstractField.parse("Content-Type: multipart/mixed; boundary=foo"));
+        headerMultipartDigest.addField(
+                AbstractField.parse("Content-Type: multipart/digest; boundary=foo"));
+    }
+
+    public void testGetMimeType() {
+        Message parent = null;
+        Message child = null;
+        
+        parent = new Message();
+        child = new Message();
+        child.setParent(parent);
+        parent.setHeader(headerMultipartDigest);
+        child.setHeader(headerEmpty);
+        assertEquals("multipart/digest, empty", "message/rfc822", 
+                child.getMimeType());
+        child.setHeader(headerTextPlain);
+        assertEquals("multipart/digest, text/plain", "text/plain", 
+                child.getMimeType());
+        child.setHeader(headerMessageRFC822);
+        assertEquals("multipart/digest, message/rfc822", "message/rfc822", 
+                child.getMimeType());
+        
+        parent = new Message();
+        child = new Message();
+        child.setParent(parent);
+        parent.setHeader(headerMultipartMixed);
+        child.setHeader(headerEmpty);
+        assertEquals("multipart/mixed, empty", "text/plain", 
+                child.getMimeType());
+        child.setHeader(headerTextPlain);
+        assertEquals("multipart/mixed, text/plain", "text/plain", 
+                child.getMimeType());
+        child.setHeader(headerMessageRFC822);
+        assertEquals("multipart/mixed, message/rfc822", "message/rfc822", 
+                child.getMimeType());
+        
+        child = new Message();
+        child.setHeader(headerEmpty);
+        assertEquals("null, empty", "text/plain", child.getMimeType());
+        child.setHeader(headerTextPlain);
+        assertEquals("null, text/plain", "text/plain", child.getMimeType());
+        child.setHeader(headerMessageRFC822);
+        assertEquals("null, message/rfc822", "message/rfc822", 
+                child.getMimeType());
+    }
+
+    public void testIsMultipart() {
+        Message m = new Message();
+        
+        m.setHeader(headerEmpty);
+        assertTrue("empty", !m.isMultipart());
+        
+        m.setHeader(headerTextPlain);
+        assertTrue("text/plain", !m.isMultipart());
+        
+        m.setHeader(headerMultipartDigest);
+        assertTrue("multipart/digest", m.isMultipart());
+        
+        m.setHeader(headerMultipartMixed);
+        assertTrue("multipart/mixed", m.isMultipart());
+    }
+    
+    public void testWriteTo() throws Exception {
+        byte[] inputByte = getRawMessageAsByteArray();
+
+        Message m = new Message(new ByteArrayInputStream(inputByte));
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        m.writeTo(out);
+
+        InputStream output = new ByteArrayInputStream(out.toByteArray());
+
+        int b = -1;
+        int i = 0;
+        while ((b = output.read()) != -1) {
+            assertEquals("same byte", b, inputByte[i]);
+            i++;
+        }
+    }
+
+    public void testAddHeaderWriteTo() throws Exception {
+        String headerName = "testheader";
+        String headerValue = "testvalue";
+        String testheader = headerName + ": " + headerValue;
+
+        byte[] inputByte = getRawMessageAsByteArray();
+
+        Message m = new Message(new ByteArrayInputStream(inputByte));
+        m.getHeader().addField(AbstractField.parse(testheader));
+
+        assertEquals("header added", m.getHeader().getField(headerName)
+                .getBody(), headerValue);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        m.writeTo(out);
+        List<?> lines = IOUtils.readLines((new BufferedReader(
+                new InputStreamReader(new ByteArrayInputStream(out
+                        .toByteArray())))));
+
+        assertTrue("header added", lines.contains(testheader));
+    }
+
+    public void testGetMessageId() throws Exception {
+        Message m = new Message();
+        assertNull(m.getMessageId());
+
+        String id = "<msg17@localhost>";
+        Header header = new Header();
+        header.setField(AbstractField.parse("Message-ID: " + id));
+        m.setHeader(header);
+        assertEquals(id, m.getMessageId());
+    }
+
+    public void testCreateMessageId() throws Exception {
+        Message m = new Message();
+        m.createMessageId("hostname");
+
+        String id = m.getMessageId();
+        assertNotNull(id);
+        assertTrue(id.startsWith("<Mime4j."));
+        assertTrue(id.endsWith("@hostname>"));
+    }
+
+    public void testGetSubject() throws Exception {
+        Message m = new Message();
+        assertNull(m.getSubject());
+
+        String subject = "testing 1 2";
+        Header header = new Header();
+        header.setField(AbstractField.parse("Subject: " + subject));
+        m.setHeader(header);
+        assertEquals(subject, m.getSubject());
+
+        header.setField(AbstractField.parse("Subject: =?windows-1252?Q?99_=80?="));
+        assertEquals("99 \u20ac", m.getSubject());
+    }
+
+    public void testSetSubject() throws Exception {
+        Message m = new Message();
+
+        m.setSubject("Semmelbr\366sel");
+        assertEquals("Semmelbr\366sel", m.getSubject());
+        assertEquals("=?ISO-8859-1?Q?Semmelbr=F6sel?=", m.getHeader().getField(
+                "Subject").getBody());
+
+        m.setSubject(null);
+        assertNull(m.getHeader().getField("Subject"));
+    }
+
+    public void testGetDate() throws Exception {
+        Message m = new Message();
+        assertNull(m.getDate());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Date: Thu, 1 Jan 1970 05:30:00 +0530"));
+        m.setHeader(header);
+
+        assertEquals(new Date(0), m.getDate());
+    }
+
+    public void testSetDate() throws Exception {
+        Message m = new Message();
+
+        m.setDate(new Date(86400000), TimeZone.getTimeZone("GMT"));
+        assertEquals(new Date(86400000), m.getDate());
+        assertEquals("Fri, 2 Jan 1970 00:00:00 +0000", m.getHeader().getField(
+                "Date").getBody());
+
+        m.setDate(null);
+        assertNull(m.getHeader().getField("Date"));
+    }
+
+    public void testGetSender() throws Exception {
+        Message m = new Message();
+        assertNull(m.getSender());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Sender: john.doe@example.net"));
+        m.setHeader(header);
+
+        assertEquals("john.doe@example.net", m.getSender().getAddress());
+    }
+
+    public void testSetSender() throws Exception {
+        Message m = new Message();
+
+        m.setSender(Mailbox.parse("john.doe@example.net"));
+        assertEquals("john.doe@example.net", m.getHeader().getField("Sender")
+                .getBody());
+
+        m.setSender(null);
+        assertNull(m.getHeader().getField("Sender"));
+    }
+
+    public void testGetFrom() throws Exception {
+        Message m = new Message();
+        assertNull(m.getFrom());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("From: john.doe@example.net"));
+        m.setHeader(header);
+
+        assertEquals("john.doe@example.net", m.getFrom().get(0).getAddress());
+    }
+
+    public void testSetFrom() throws Exception {
+        Message m = new Message();
+
+        Mailbox mailbox1 = Mailbox.parse("john.doe@example.net");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.net");
+
+        m.setFrom(mailbox1);
+        assertEquals("john.doe@example.net", m.getHeader().getField("From")
+                .getBody());
+
+        m.setFrom(mailbox1, mailbox2);
+        assertEquals("john.doe@example.net, jane.doe@example.net", m
+                .getHeader().getField("From").getBody());
+
+        m.setFrom(Arrays.asList(mailbox1, mailbox2));
+        assertEquals("john.doe@example.net, jane.doe@example.net", m
+                .getHeader().getField("From").getBody());
+
+        m.setFrom((Mailbox) null);
+        assertNull(m.getHeader().getField("From"));
+    }
+
+    public void testGetTo() throws Exception {
+        Message m = new Message();
+        assertNull(m.getTo());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("To: john.doe@example.net"));
+        m.setHeader(header);
+
+        assertEquals("john.doe@example.net", ((Mailbox) m.getTo().get(0))
+                .getAddress());
+    }
+
+    public void testSetTo() throws Exception {
+        Message m = new Message();
+
+        Mailbox mailbox1 = Mailbox.parse("john.doe@example.net");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.net");
+        Group group = new Group("Does", mailbox1, mailbox2);
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+
+        m.setTo(group);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;", m
+                .getHeader().getField("To").getBody());
+
+        m.setTo(group, mailbox3);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader().getField("To")
+                .getBody());
+
+        m.setTo(Arrays.asList(group, mailbox3));
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader().getField("To")
+                .getBody());
+
+        m.setTo((Mailbox) null);
+        assertNull(m.getHeader().getField("To"));
+    }
+
+    public void testGetCc() throws Exception {
+        Message m = new Message();
+        assertNull(m.getCc());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Cc: john.doe@example.net"));
+        m.setHeader(header);
+
+        assertEquals("john.doe@example.net", ((Mailbox) m.getCc().get(0))
+                .getAddress());
+    }
+
+    public void testSetCc() throws Exception {
+        Message m = new Message();
+
+        Mailbox mailbox1 = Mailbox.parse("john.doe@example.net");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.net");
+        Group group = new Group("Does", mailbox1, mailbox2);
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+
+        m.setCc(group);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;", m
+                .getHeader().getField("Cc").getBody());
+
+        m.setCc(group, mailbox3);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader().getField("Cc")
+                .getBody());
+
+        m.setCc(Arrays.asList(group, mailbox3));
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader().getField("Cc")
+                .getBody());
+
+        m.setCc((Mailbox) null);
+        assertNull(m.getHeader().getField("Cc"));
+    }
+
+    public void testGetBcc() throws Exception {
+        Message m = new Message();
+        assertNull(m.getBcc());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Bcc: john.doe@example.net"));
+        m.setHeader(header);
+
+        assertEquals("john.doe@example.net", ((Mailbox) m.getBcc().get(0))
+                .getAddress());
+    }
+
+    public void testSetBcc() throws Exception {
+        Message m = new Message();
+
+        Mailbox mailbox1 = Mailbox.parse("john.doe@example.net");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.net");
+        Group group = new Group("Does", mailbox1, mailbox2);
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+
+        m.setBcc(group);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;", m
+                .getHeader().getField("Bcc").getBody());
+
+        m.setBcc(group, mailbox3);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader()
+                .getField("Bcc").getBody());
+
+        m.setBcc(Arrays.asList(group, mailbox3));
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader()
+                .getField("Bcc").getBody());
+
+        m.setBcc((Mailbox) null);
+        assertNull(m.getHeader().getField("Bcc"));
+    }
+
+    public void testGetReplyTo() throws Exception {
+        Message m = new Message();
+        assertNull(m.getReplyTo());
+
+        Header header = new Header();
+        header.setField(AbstractField.parse("Reply-To: john.doe@example.net"));
+        m.setHeader(header);
+
+        assertEquals("john.doe@example.net", ((Mailbox) m.getReplyTo().get(0))
+                .getAddress());
+    }
+
+    public void testSetReplyTo() throws Exception {
+        Message m = new Message();
+
+        Mailbox mailbox1 = Mailbox.parse("john.doe@example.net");
+        Mailbox mailbox2 = Mailbox.parse("jane.doe@example.net");
+        Group group = new Group("Does", mailbox1, mailbox2);
+        Mailbox mailbox3 = Mailbox.parse("Mary Smith <mary@example.net>");
+
+        m.setReplyTo(group);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;", m
+                .getHeader().getField("Reply-To").getBody());
+
+        m.setReplyTo(group, mailbox3);
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader().getField(
+                "Reply-To").getBody());
+
+        m.setReplyTo(Arrays.asList(group, mailbox3));
+        assertEquals("Does: john.doe@example.net, jane.doe@example.net;, "
+                + "Mary Smith <mary@example.net>", m.getHeader().getField(
+                "Reply-To").getBody());
+
+        m.setReplyTo((Mailbox) null);
+        assertNull(m.getHeader().getField("Reply-To"));
+    }
+
+    public void testDisposeGetsPropagatedToBody() throws Exception {
+        DummyBody body1 = new DummyBody();
+        BodyPart part1 = new BodyPart();
+        part1.setHeader(headerEmpty);
+        part1.setBody(body1);
+
+        DummyBody body2 = new DummyBody();
+        BodyPart part2 = new BodyPart();
+        part2.setHeader(headerEmpty);
+        part2.setBody(body2);
+
+        Multipart mp = new Multipart("mixed");
+        mp.addBodyPart(part1);
+        mp.addBodyPart(part2);
+
+        Message m = new Message();
+        m.setHeader(headerMultipartMixed);
+        m.setBody(mp);
+
+        assertFalse(body1.disposed);
+        assertFalse(body2.disposed);
+
+        m.dispose();
+
+        assertTrue(body1.disposed);
+        assertTrue(body2.disposed);
+    }
+
+    private byte[] getRawMessageAsByteArray() {
+        StringBuilder header = new StringBuilder();
+        StringBuilder body = new StringBuilder();
+        StringBuilder complete = new StringBuilder();
+
+        header.append("Date: Wed, 21 Feb 2007 11:09:27 +0100\r\n");
+        header.append("From: Test <test@test>\r\n");
+        header.append("To: Norman Maurer <nm@byteaction.de>\r\n");
+        header.append("Subject: Testmail\r\n");
+        header
+                .append("Content-Type: text/plain; charset=ISO-8859-15; format=flowed\r\n");
+        header.append("Content-Transfer-Encoding: 8bit\r\n\r\n");
+        body.append("testbody\r\n");
+        complete.append(header);
+        complete.append(body);
+
+        return complete.toString().getBytes();
+    }
+
+    private static final class DummyBody extends SingleBody {
+
+        public boolean disposed = false;
+
+        @Override
+        public void writeTo(OutputStream out) throws IOException {
+            out.write("dummy".getBytes("US-ASCII"));
+        }
+
+        @Override
+        public void dispose() {
+            disposed = true;
+        }
+
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java
new file mode 100644
index 0000000..f8c3c00
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java
@@ -0,0 +1,71 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.apache.james.mime4j.ExampleMail;
+
+import junit.framework.TestCase;
+
+public class MessageWriteToTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testSimpleMail() throws Exception {
+        Message message = createMessage(ExampleMail.RFC822_SIMPLE_BYTES);
+        assertFalse("Not multipart", message.isMultipart());
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        message.writeTo(out);
+        assertEquals(out.toByteArray(), ExampleMail.RFC822_SIMPLE_BYTES);
+    }
+    
+    private void assertEquals(byte[] expected, byte[] actual) {
+        StringBuilder buffer = new StringBuilder(expected.length);
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < actual.length; i++) {
+            buffer.append((char)actual[i]);
+            assertEquals("Mismatch@" + i, expected[i], actual[i]);
+        }
+    }
+    
+    public void testBinaryAttachment() throws Exception {
+        Message message = createMessage(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES);
+        assertTrue("Is multipart", message.isMultipart());
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        message.writeTo(out);
+        assertEquals(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES, out.toByteArray());
+    }
+    
+    private Message createMessage(byte[] octets) throws Exception {
+        ByteArrayInputStream in = new ByteArrayInputStream(octets);
+        Message message = new Message(in);
+        return message;
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java
new file mode 100644
index 0000000..487d5a1
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java
@@ -0,0 +1,83 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.field.AbstractField;
+
+public class MultipartFormTest extends TestCase {
+
+    public void testMultipartFormContent() throws Exception {
+        BodyFactory bodyFactory = new BodyFactory();
+        
+        Message message = new Message();
+        Header header = new Header();
+        header.addField(
+                AbstractField.parse("Content-Type: multipart/form-data; boundary=foo"));
+        message.setHeader(header);
+        
+        Multipart multipart = new Multipart("alternative");
+        multipart.setParent(message);
+        BodyPart p1 = new BodyPart();
+        Header h1 = new Header();
+        h1.addField(AbstractField.parse("Content-Type: text/plain"));
+        p1.setHeader(h1);
+        p1.setBody(bodyFactory.textBody("this stuff"));
+        BodyPart p2 = new BodyPart();
+        Header h2 = new Header();
+        h2.addField(AbstractField.parse("Content-Type: text/plain"));
+        p2.setHeader(h2);
+        p2.setBody(bodyFactory.textBody("that stuff"));
+        BodyPart p3 = new BodyPart();
+        Header h3 = new Header();
+        h3.addField(AbstractField.parse("Content-Type: text/plain"));
+        p3.setHeader(h3);
+        p3.setBody(bodyFactory.textBody("all kind of stuff"));
+
+        multipart.addBodyPart(p1);
+        multipart.addBodyPart(p2);
+        multipart.addBodyPart(p3);
+        
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        MessageWriter.DEFAULT.writeMultipart(multipart, out);
+        out.close();
+        
+        String expected = "\r\n" + 
+            "--foo\r\n" +
+            "Content-Type: text/plain\r\n" +
+            "\r\n" +
+            "this stuff\r\n" +
+            "--foo\r\n" +
+            "Content-Type: text/plain\r\n" +
+            "\r\n" +
+            "that stuff\r\n" +
+            "--foo\r\n" +
+            "Content-Type: text/plain\r\n" +
+            "\r\n" +
+            "all kind of stuff\r\n" +
+            "--foo--\r\n";
+        String s = out.toString("US-ASCII");
+        assertEquals(expected, s);
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
new file mode 100644
index 0000000..93f0ac8
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
@@ -0,0 +1,129 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.storage.MemoryStorageProvider;
+import org.apache.james.mime4j.storage.MultiReferenceStorage;
+import org.apache.james.mime4j.storage.Storage;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class SingleBodyCopyTest extends TestCase {
+
+    public void testCopyStorageBinaryBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageBinaryBody(multiReferenceStorage);
+        copyTest(body);
+    }
+
+    public void testCopyStorageTextBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageTextBody(multiReferenceStorage,
+                CharsetUtil.US_ASCII);
+        copyTest(body);
+    }
+
+    public void testCopyStringTextBody() throws Exception {
+        SingleBody body = new StringTextBody("test", CharsetUtil.US_ASCII);
+        copyTest(body);
+    }
+
+    public void testDisposeStorageBinaryBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageBinaryBody(multiReferenceStorage);
+        disposeTest(body, storage);
+    }
+
+    public void testDisposeStorageTextBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageTextBody(multiReferenceStorage,
+                CharsetUtil.US_ASCII);
+        disposeTest(body, storage);
+    }
+
+    private void copyTest(SingleBody body) throws Exception {
+        Message parent = new Message();
+        parent.setBody(body);
+
+        SingleBody copy = body.copy();
+        assertNotNull(copy);
+        assertNotSame(body, copy);
+
+        assertSame(parent, body.getParent());
+        assertNull(copy.getParent());
+
+        sameContentTest(body, copy);
+    }
+
+    private void sameContentTest(SingleBody expectedBody, SingleBody actualBody)
+            throws Exception {
+        ByteArrayOutputStream expBaos = new ByteArrayOutputStream();
+        expectedBody.writeTo(expBaos);
+        byte[] expected = expBaos.toByteArray();
+
+        ByteArrayOutputStream actBaos = new ByteArrayOutputStream();
+        actualBody.writeTo(actBaos);
+        byte[] actual = actBaos.toByteArray();
+
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+
+    private void disposeTest(SingleBody body, Storage storage) throws Exception {
+        assertTrue(storageIsReadable(storage));
+
+        SingleBody copy = body.copy();
+        assertTrue(storageIsReadable(storage));
+
+        body.dispose();
+        assertTrue(storageIsReadable(storage));
+
+        copy.dispose();
+        assertFalse(storageIsReadable(storage));
+    }
+
+    private boolean storageIsReadable(Storage storage) throws Exception {
+        try {
+            storage.getInputStream().close();
+            return true;
+        } catch (IllegalStateException e) {
+            return false;
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
new file mode 100644
index 0000000..09e9ef0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeEntityTest.java
@@ -0,0 +1,540 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+import java.io.ByteArrayInputStream;

+import java.io.IOException;

+

+import org.apache.commons.io.IOUtils;

+import org.apache.james.mime4j.io.BufferedLineReaderInputStream;

+import org.apache.james.mime4j.io.MaxHeaderLimitException;

+import org.apache.james.mime4j.io.MaxLineLimitException;

+import org.apache.james.mime4j.io.LineNumberInputStream;

+import org.apache.james.mime4j.parser.EntityStateMachine;

+import org.apache.james.mime4j.parser.EntityStates;

+import org.apache.james.mime4j.parser.MimeEntity;

+import org.apache.james.mime4j.parser.RecursionMode;

+

+import junit.framework.TestCase;

+

+public class MimeEntityTest extends TestCase {

+

+    public void testSimpleEntity() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "Content-Type: text/plain\r\n" +

+            "\r\n" +

+            "a very important message";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 12); 

+        

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE);

+        

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("To", entity.getField().getName());

+        assertEquals(" Road Runner <runner@example.org>", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("From", entity.getField().getName());

+        assertEquals(" Wile E. Cayote <wile@example.org>", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Date", entity.getField().getName());

+        assertEquals(" Tue, 12 Feb 2008 17:34:09 +0000 (GMT)", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Subject", entity.getField().getName());

+        assertEquals(" Mail", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Content-Type", entity.getField().getName());

+        assertEquals(" text/plain", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_END_HEADER, entity.getState());

+        try {

+            entity.getField().getName();

+            fail("IllegalStateException should have been thrown");

+        } catch (IllegalStateException expected) {

+        }

+        try {

+            entity.getField().getBody();

+            fail("IllegalStateException should have been thrown");

+        } catch (IllegalStateException expected) {

+        }

+        

+        entity.advance();

+        assertEquals(EntityStates.T_BODY, entity.getState());

+        assertEquals("a very important message", IOUtils.toString(entity.getContentStream()));

+        entity.advance();

+        assertEquals(EntityStates.T_END_MESSAGE, entity.getState());

+        try {

+            entity.getContentStream();

+            fail("IllegalStateException should have been thrown");

+        } catch (IllegalStateException expected) {

+        }

+        entity.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, entity.getState());

+        try {

+            entity.advance();

+            fail("IllegalStateException should have been thrown");

+        } catch (IllegalStateException expected) {

+        }

+    }

+

+    public void testMultipartEntity() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "Content-Type: multipart/mixed;boundary=1729\r\n" +

+            "\r\n" +

+            "Hello!\r\n" +

+            "--1729\r\n" +

+            "Content-Type: text/plain; charset=US-ASCII\r\n" +

+            "\r\n" +

+            "blah blah blah\r\n" +

+            "--1729\r\n" +

+            "Content-Type: text/plain; charset=US-ASCII\r\n" +

+            "\r\n" +

+            "yada yada yada\r\n" +

+            "--1729--\r\n" +

+            "Goodbye!";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 24); 

+        

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE);

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("To", entity.getField().getName());

+        assertEquals(" Road Runner <runner@example.org>", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("From", entity.getField().getName());

+        assertEquals(" Wile E. Cayote <wile@example.org>", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Date", entity.getField().getName());

+        assertEquals(" Tue, 12 Feb 2008 17:34:09 +0000 (GMT)", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Subject", entity.getField().getName());

+        assertEquals(" Mail", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Content-Type", entity.getField().getName());

+        assertEquals(" multipart/mixed;boundary=1729", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_END_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_MULTIPART, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_PREAMBLE, entity.getState());

+        assertEquals("Hello!", IOUtils.toString(entity.getContentStream()));

+        

+        EntityStateMachine p1 = entity.advance();

+        assertNotNull(p1);

+        

+        assertEquals(EntityStates.T_START_BODYPART, p1.getState());

+        p1.advance();

+        assertEquals(EntityStates.T_START_HEADER, p1.getState());

+        p1.advance();

+        assertEquals(EntityStates.T_FIELD, p1.getState());

+        assertEquals("Content-Type", p1.getField().getName());

+        assertEquals(" text/plain; charset=US-ASCII", p1.getField().getBody());

+        p1.advance();

+        assertEquals(EntityStates.T_END_HEADER, p1.getState());

+        p1.advance();

+        assertEquals(EntityStates.T_BODY, p1.getState());

+        assertEquals("blah blah blah", IOUtils.toString(p1.getContentStream()));

+        p1.advance();

+        assertEquals(EntityStates.T_END_BODYPART, p1.getState());

+        p1.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, p1.getState());

+

+        EntityStateMachine p2 = entity.advance();

+        assertNotNull(p2);

+        

+        assertEquals(EntityStates.T_START_BODYPART, p2.getState());

+        p2.advance();

+        assertEquals(EntityStates.T_START_HEADER, p2.getState());

+        p2.advance();

+        assertEquals(EntityStates.T_FIELD, p2.getState());

+        assertEquals("Content-Type", p2.getField().getName());

+        assertEquals(" text/plain; charset=US-ASCII", p2.getField().getBody());

+        p2.advance();

+        assertEquals(EntityStates.T_END_HEADER, p2.getState());

+        p2.advance();

+        assertEquals(EntityStates.T_BODY, p2.getState());

+        assertEquals("yada yada yada", IOUtils.toString(p2.getContentStream()));

+        p2.advance();

+        assertEquals(EntityStates.T_END_BODYPART, p2.getState());

+        p2.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, p2.getState());

+

+        entity.advance();

+        assertEquals(EntityStates.T_EPILOGUE, entity.getState());

+        assertEquals("Goodbye!", IOUtils.toString(entity.getContentStream()));

+        entity.advance();

+        assertEquals(EntityStates.T_END_MULTIPART, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_END_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, entity.getState());

+    }

+    

+    public void testRawEntity() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "Content-Type: multipart/mixed;boundary=1729\r\n" +

+            "\r\n" +

+            "Hello!\r\n" +

+            "--1729\r\n" +

+            "Content-Type: text/plain; charset=US-ASCII\r\n" +

+            "\r\n" +

+            "blah blah blah\r\n" +

+            "--1729\r\n" +

+            "Content-Type: text/plain; charset=US-ASCII\r\n" +

+            "\r\n" +

+            "yada yada yada\r\n" +

+            "--1729--\r\n" +

+            "Goodbye!";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 24); 

+        

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE);

+        

+        entity.setRecursionMode(RecursionMode.M_RAW);

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("To", entity.getField().getName());

+        assertEquals(" Road Runner <runner@example.org>", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("From", entity.getField().getName());

+        assertEquals(" Wile E. Cayote <wile@example.org>", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Date", entity.getField().getName());

+        assertEquals(" Tue, 12 Feb 2008 17:34:09 +0000 (GMT)", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Subject", entity.getField().getName());

+        assertEquals(" Mail", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        assertEquals("Content-Type", entity.getField().getName());

+        assertEquals(" multipart/mixed;boundary=1729", entity.getField().getBody());

+        entity.advance();

+        assertEquals(EntityStates.T_END_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_MULTIPART, entity.getState());

+        

+        entity.advance();

+        assertEquals(EntityStates.T_PREAMBLE, entity.getState());

+        assertEquals("Hello!", IOUtils.toString(entity.getContentStream()));

+        

+        EntityStateMachine p1 = entity.advance();

+        assertNotNull(p1);

+        

+        assertEquals(EntityStates.T_RAW_ENTITY, p1.getState());

+        assertNull(p1.getBodyDescriptor());

+        assertNull(p1.getField());

+        assertEquals(

+                "Content-Type: text/plain; charset=US-ASCII\r\n" +

+                "\r\n" +

+                "blah blah blah", IOUtils.toString(p1.getContentStream()));

+        p1.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, p1.getState());

+

+        EntityStateMachine p2 = entity.advance();

+        assertNotNull(p2);

+        

+        assertEquals(EntityStates.T_RAW_ENTITY, p2.getState());

+        assertNull(p2.getBodyDescriptor());

+        assertNull(p2.getField());

+        assertEquals(

+                "Content-Type: text/plain; charset=US-ASCII\r\n" +

+                "\r\n" +

+                "yada yada yada", IOUtils.toString(p2.getContentStream()));

+        p2.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, p2.getState());

+

+        entity.advance();

+        assertEquals(EntityStates.T_EPILOGUE, entity.getState());

+        assertEquals("Goodbye!", IOUtils.toString(entity.getContentStream()));

+        entity.advance();

+        assertEquals(EntityStates.T_END_MULTIPART, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_END_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_END_OF_STREAM, entity.getState());

+    }

+

+    public void testMaxLineLimitCheck() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "Content-Type: text/plain\r\n" +

+            "\r\n" +

+            "a very important message";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 12); 

+        

+        MimeEntityConfig config = new MimeEntityConfig();

+        config.setMaxLineLen(50);

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE,

+                config);

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        try {

+            entity.advance();

+            fail("MaxLineLimitException should have been thrown");

+        } catch (MaxLineLimitException expected) {

+        }

+    }

+    

+    public void testMaxLineLimitCheckFoldedLines() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "    xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "Content-Type: text/plain\r\n" +

+            "\r\n" +

+            "a very important message";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 12); 

+        

+        MimeEntityConfig config = new MimeEntityConfig();

+        config.setMaxLineLen(50);

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE,

+                config);

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        try {

+            entity.advance();

+            fail("MaxLineLimitException should have been thrown");

+        } catch (MaxLineLimitException expected) {

+        }

+    }

+

+    public void testMaxHeaderCount() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "DoS: xxxxxxxxxxxxxxxxxxxxx\r\n" +

+            "Content-Type: text/plain\r\n" +

+            "\r\n" +

+            "a very important message";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 12); 

+        

+        MimeEntityConfig config = new MimeEntityConfig();

+        config.setMaxHeaderCount(20);

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE,

+                config);

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        

+        for (int i = 0; i < 20; i++) {

+            entity.advance();

+            assertEquals(EntityStates.T_FIELD, entity.getState());

+        }

+        try {

+            entity.advance();

+            fail("MaxHeaderLimitException should have been thrown");

+        } catch (MaxHeaderLimitException expected) {

+        }

+    }

+

+    public void testMaxContentLimitCheck() throws Exception {

+        String message = 

+            "To: Road Runner <runner@example.org>\r\n" +

+            "From: Wile E. Cayote <wile@example.org>\r\n" +

+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +

+            "Subject: Mail\r\n" +

+            "Content-Type: text/plain\r\n" +

+            "\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n" +

+            "DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS DoS\r\n";

+        byte[] raw = message.getBytes("US-ASCII");

+        ByteArrayInputStream instream = new ByteArrayInputStream(raw);

+        LineNumberInputStream lineInput = new LineNumberInputStream(instream); 

+        BufferedLineReaderInputStream rawstream = new BufferedLineReaderInputStream(lineInput, 12); 

+        

+        MimeEntityConfig config = new MimeEntityConfig();

+        config.setMaxContentLen(100);

+        MimeEntity entity = new MimeEntity(

+                lineInput,

+                rawstream,

+                null,

+                EntityStates.T_START_MESSAGE,

+                EntityStates.T_END_MESSAGE,

+                config);

+        

+        assertEquals(EntityStates.T_START_MESSAGE, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_START_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_FIELD, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_END_HEADER, entity.getState());

+        entity.advance();

+        assertEquals(EntityStates.T_BODY, entity.getState());

+        try {

+            IOUtils.toByteArray(entity.getContentStream());

+            fail("IOException should have been thrown");

+        } catch (IOException expected) {

+        }

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamParserExampleMessagesTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamParserExampleMessagesTest.java
new file mode 100644
index 0000000..4b843f6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamParserExampleMessagesTest.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.log4j.BasicConfigurator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Creates a TestSuite running the test for each .msg file in the test resouce folder.
+ * Allow running of a single test from Unit testing GUIs
+ */
+public class MimeStreamParserExampleMessagesTest extends TestCase {
+
+    private File file;
+
+
+    public MimeStreamParserExampleMessagesTest(String testName) {
+        this(testName, MimeStreamParserExampleMessagesTestSuite.getFile(testName));
+    }
+
+    public MimeStreamParserExampleMessagesTest(String name, File testFile) {
+        super(name);
+        this.file = testFile;
+    }
+
+    @Override
+    public void setUp() {
+        BasicConfigurator.resetConfiguration();
+        BasicConfigurator.configure();
+    }
+   
+    @Override
+    protected void runTest() throws Throwable {
+        MimeStreamParser parser = null;
+        TestHandler handler = null;
+        MimeEntityConfig config = new MimeEntityConfig();
+        config.setMaxLineLen(-1);
+        parser = new MimeStreamParser(config);
+        handler = new TestHandler();
+        
+        System.out.println("Parsing " + file.getName());
+        parser.setContentHandler(handler);
+        parser.parse(new FileInputStream(file));
+        
+        String result = handler.sb.toString();
+        String xmlFile = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + ".xml";
+        String xmlFileMime4j = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + ".mime4j.xml";
+        
+        try {
+            String expected = IOUtils.toString(new FileInputStream(xmlFile), "ISO8859-1");
+            assertEquals("Error parsing " + file.getName(), expected, result);
+        } catch (FileNotFoundException e) {
+            FileOutputStream fos = new FileOutputStream(xmlFileMime4j);
+            fos.write(result.getBytes());
+            fos.flush();
+            fos.close();
+            fail("XML file not found: generated a file with the expected result!");
+        }
+    }
+
+    public static Test suite() throws IOException {
+        return new MimeStreamParserExampleMessagesTestSuite();
+    }
+
+    
+    static class MimeStreamParserExampleMessagesTestSuite extends TestSuite {
+
+        private static final File TESTS_FOLDER = new File("src/test/resources/testmsgs");
+
+        public MimeStreamParserExampleMessagesTestSuite() throws IOException {
+            super();
+            File dir = TESTS_FOLDER;
+            File[] files = dir.listFiles();
+            
+            for (File f : files) {
+                if (f.getName().toLowerCase().endsWith(".msg")) {
+                    addTest(new MimeStreamParserExampleMessagesTest(f.getName().substring(0, f.getName().length()-4), f));
+                }
+            }
+        }
+        
+        public static File getFile(String name) {
+            return new File(TESTS_FOLDER.getAbsolutePath()+File.separator+name+".msg");
+        }
+
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamParserTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamParserTest.java
new file mode 100644
index 0000000..93cd4a2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamParserTest.java
@@ -0,0 +1,475 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.parser;

+

+import org.apache.james.mime4j.descriptor.BodyDescriptor;

+import org.apache.james.mime4j.parser.AbstractContentHandler;

+import org.apache.james.mime4j.parser.MimeStreamParser;

+import org.apache.james.mime4j.util.ByteSequence;

+import org.apache.james.mime4j.util.ContentUtil;

+import org.apache.log4j.BasicConfigurator;

+

+import java.io.ByteArrayInputStream;

+import java.io.IOException;

+import java.io.InputStream;

+import java.util.LinkedList;

+

+import junit.framework.TestCase;

+

+public class MimeStreamParserTest extends TestCase {

+

+    @Override

+    public void setUp() {

+        BasicConfigurator.resetConfiguration();

+        BasicConfigurator.configure();

+    }

+        /*

+    public void testRootAndBodyStreamsAreSynched() throws IOException {

+        File dir = new File("testmsgs");

+        File[] files = dir.listFiles();

+        

+        for (int i = 0; i < files.length; i++) {

+            File f = files[i];

+            

+            if (f.getName().toLowerCase().endsWith(".msg")) {

+                final RandomAccessFile file = new RandomAccessFile(f, "r");

+                final EOLTrackingInputStream rootStream = 

+                    new EOLTrackingInputStream(

+                       new RandomAccessFileInputStream(file, 0, file.length()));

+                

+                ContentHandler handler = new AbstractContentHandler() {

+                    public void body(BodyDescriptor bd, InputStream expected) throws IOException {

+                       int pos = rootStream.getMark();

+                       if (expected instanceof RootInputStream) {

+                           pos++;

+                       }

+                       InputStream actual = 

+                           new EOLConvertingInputStream(

+                                 new RandomAccessFileInputStream(file, pos, file.length()));

+                       

+                       StringBuilder sb1 = new StringBuilder();

+                       StringBuilder sb2 = new StringBuilder();

+                       int b = 0;

+                       while ((b = expected.read()) != -1) {

+                           sb1.append((char) (b & 0xff));

+                           sb2.append((char) (actual.read() & 0xff));

+                       }

+                       assertEquals(sb1.toString(), sb2.toString());

+                    }

+                };

+                

+                System.out.println("Testing synch of " + f.getName());

+                

+                MimeStreamParser parser = new MimeStreamParser();

+                parser.setContentHandler(handler);

+                parser.parse(rootStream);

+            }

+        }

+    }*/

+    

+    public void testBoundaryInEpilogue() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        sb.append("From: foo@bar.com\r\n");

+        sb.append("To: someone@else.com\r\n");

+        sb.append("Content-type: multipart/something; boundary=myboundary\r\n");

+        sb.append("\r\n");

+        sb.append("This is the preamble.\r\n");

+        sb.append("--myboundary\r\n");

+        sb.append("Content-type: text/plain\r\n");

+        sb.append("\r\n");

+        sb.append("This is the first body.\r\n");

+        sb.append("It's completely meaningless.\r\n");

+        sb.append("After this line the body ends.\r\n");

+        sb.append("\r\n");

+        sb.append("--myboundary--\r\n");

+        

+        StringBuilder epilogue = new StringBuilder();

+        epilogue.append("Content-type: text/plain\r\n");

+        epilogue.append("\r\n");

+        epilogue.append("This is actually the epilogue but it looks like a second body.\r\n");

+        epilogue.append("Yada yada yada.\r\n");

+        epilogue.append("\r\n");

+        epilogue.append("--myboundary--\r\n");

+        epilogue.append("This is still the epilogue.\r\n");

+        

+        sb.append(epilogue.toString());

+        

+        ByteArrayInputStream bais = new ByteArrayInputStream(sb.toString().getBytes("US-ASCII"));

+        

+        final StringBuilder actual = new StringBuilder();

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void epilogue(InputStream is) throws IOException {

+                int b;

+                while ((b = is.read()) != -1) {

+                    actual.append((char) b);

+                }

+            }

+        });

+        parser.parse(bais);

+        

+        assertEquals(epilogue.toString(), actual.toString());

+    }

+    

+    public void testParseOneLineFields() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        final LinkedList<String> expected = new LinkedList<String>();

+        expected.add("From: foo@abr.com");

+        sb.append(expected.getLast() + "\r\n");

+        expected.add("Subject: A subject");

+        sb.append(expected.getLast() + "\r\n");

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+    }

+    

+    public void testCRWithoutLFInHeader() throws Exception {

+        /*

+         * Test added because \r:s not followed by \n:s in the header would

+         * cause an infinite loop. 

+         */

+        StringBuilder sb = new StringBuilder();

+        final LinkedList<String> expected = new LinkedList<String>();

+        expected.add("The-field: This field\r\rcontains CR:s\r\r"

+                        + "not\r\n\tfollowed by LF");

+        sb.append(expected.getLast() + "\r\n");

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+    }

+    

+    public void testParseMultiLineFields() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        final LinkedList<String> expected = new LinkedList<String>();

+        expected.add("Received: by netmbx.netmbx.de (/\\==/\\ Smail3.1.28.1)\r\n"

+                   + "\tfrom mail.cs.tu-berlin.de with smtp\r\n"

+                   + "\tid &lt;m0uWPrO-0004wpC&gt;;"

+                        + " Wed, 19 Jun 96 18:12 MES");

+        sb.append(expected.getLast() + "\r\n");

+        expected.add("Subject: A folded subject\r\n Line 2\r\n\tLine 3");

+        sb.append(expected.getLast() + "\r\n");

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+    }

+    

+    public void testStop() throws Exception {

+        final MimeStreamParser parser = new MimeStreamParser();

+        TestHandler handler = new TestHandler() {

+            @Override

+            public void endHeader() {

+                super.endHeader();

+                parser.stop();

+            }

+        };

+        parser.setContentHandler(handler);

+

+        String msg = "Subject: Yada yada\r\n"

+                   + "From: foo@bar.com\r\n"

+                   + "\r\n"

+                   + "Line 1\r\n"

+                   + "Line 2\r\n";

+        String expected = "<message>\r\n"

+                        + "<header>\r\n"

+                        + "<field>\r\n"

+                        + "Subject: Yada yada"

+                        + "</field>\r\n"

+                        + "<field>\r\n"

+                        + "From: foo@bar.com"

+                        + "</field>\r\n"

+                        + "</header>\r\n"

+                        + "<body>\r\n"

+                        + "</body>\r\n"

+                        + "</message>\r\n";

+        

+        parser.parse(new ByteArrayInputStream(msg.getBytes()));

+        String result = handler.sb.toString();

+        

+        assertEquals(expected, result);

+    }

+    

+    /*

+     * Tests that invalid fields are ignored.

+     */

+    public void testInvalidFields() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        final LinkedList<String> expected = new LinkedList<String>();

+        sb.append("From - foo@abr.com\r\n");

+        expected.add("From: some@one.com");

+        sb.append(expected.getLast() + "\r\n");

+        expected.add("Subject: A subject");

+        sb.append(expected.getLast() + "\r\n");

+        sb.append("A line which should be ignored\r\n");

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+    }

+

+    /*

+     * Tests that empty streams still generate the expected series of events.

+     */

+    public void testEmptyStream() throws Exception {

+        final LinkedList<String> expected = new LinkedList<String>();

+        expected.add("startMessage");

+        expected.add("startHeader");

+        expected.add("endHeader");

+        expected.add("body");

+        expected.add("endMessage");

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void body(BodyDescriptor bd, InputStream is) {

+                assertEquals(expected.removeFirst(), "body");

+            }

+            

+            @Override

+            public void endMultipart() {

+                fail("endMultipart shouldn't be called for empty stream");

+            }

+

+            @Override

+            public void endBodyPart() {

+                fail("endBodyPart shouldn't be called for empty stream");

+            }

+

+            @Override

+            public void endHeader() {

+                assertEquals(expected.removeFirst(), "endHeader");

+            }

+

+            @Override

+            public void endMessage() {

+                assertEquals(expected.removeFirst(), "endMessage");

+            }

+

+            @Override

+            public void field(Field field) {

+                fail("field shouldn't be called for empty stream");

+            }

+

+            @Override

+            public void startMultipart(BodyDescriptor bd) {

+                fail("startMultipart shouldn't be called for empty stream");

+            }

+

+            @Override

+            public void startBodyPart() {

+                fail("startBodyPart shouldn't be called for empty stream");

+            }

+

+            @Override

+            public void startHeader() {

+                assertEquals(expected.removeFirst(), "startHeader");

+            }

+

+            @Override

+            public void startMessage() {

+                assertEquals(expected.removeFirst(), "startMessage");

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(new byte[0]));

+        

+        assertEquals(0, expected.size());

+    }

+    

+    /*

+     * Tests parsing of empty headers.

+     */

+    public void testEmpyHeader() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        sb.append("\r\n");

+        sb.append("The body is right here\r\n");

+        

+        final StringBuilder body = new StringBuilder();

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                fail("No fields should be reported");

+            }

+            @Override

+            public void body(BodyDescriptor bd, InputStream is) throws IOException {

+                int b;

+                while ((b = is.read()) != -1) {

+                    body.append((char) b);

+                }

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals("The body is right here\r\n", body.toString());

+    }

+    

+    /*

+     * Tests parsing of empty body.

+     */

+    public void testEmptyBody() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        final LinkedList<String> expected = new LinkedList<String>();

+        expected.add("From: some@one.com");

+        sb.append(expected.getLast() + "\r\n");

+        expected.add("Subject: A subject");

+        sb.append(expected.getLast() + "\r\n\r\n");

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+            @Override

+            public void body(BodyDescriptor bd, InputStream is) throws IOException {

+                assertEquals(-1, is.read());

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+    }

+    

+    /*

+     * Tests that invalid fields are ignored.

+     */

+    public void testPrematureEOFAfterFields() throws Exception {

+        StringBuilder sb = new StringBuilder();

+        final LinkedList<String> expected = new LinkedList<String>();

+        expected.add("From: some@one.com");

+        sb.append(expected.getLast() + "\r\n");

+        expected.add("Subject: A subject");

+        sb.append(expected.getLast());

+        

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+        

+        sb = new StringBuilder();

+        expected.clear();

+        expected.add("From: some@one.com");

+        sb.append(expected.getLast() + "\r\n");

+        expected.add("Subject: A subject");

+        sb.append(expected.getLast() + "\r\n");

+        

+        parser = new MimeStreamParser();

+        parser.setContentHandler(new AbstractContentHandler() {

+            @Override

+            public void field(Field field) {

+                assertEquals(expected.removeFirst(), decode(field.getRaw()));

+            }

+        });

+        

+        parser.parse(new ByteArrayInputStream(sb.toString().getBytes()));

+        

+        assertEquals(0, expected.size());

+    }

+    

+    public void testAutomaticContentDecoding() throws Exception {

+        MimeStreamParser parser = new MimeStreamParser();

+        parser.setContentDecoding(true);

+        TestHandler handler = new TestHandler();

+        parser.setContentHandler(handler);

+

+        String msg = "Subject: Yada yada\r\n"

+                   + "From: foo@bar.com\r\n"

+                   + "Content-Type: application/octet-stream\r\n"

+                   + "Content-Transfer-Encoding: base64\r\n"

+                   + "\r\n"

+                   + "V2hvIGF0ZSBteSBjYWtlPwo=";

+        String expected = "<message>\r\n"

+                        + "<header>\r\n"

+                        + "<field>\r\n"

+                        + "Subject: Yada yada"

+                        + "</field>\r\n"

+                        + "<field>\r\n"

+                        + "From: foo@bar.com"

+                        + "</field>\r\n"

+                        + "<field>\r\n"

+                        + "Content-Type: application/octet-stream"

+                        + "</field>\r\n"

+                        + "<field>\r\n"

+                        + "Content-Transfer-Encoding: base64"

+                        + "</field>\r\n"

+                        + "</header>\r\n"

+                        + "<body>\r\n"

+                        + "Who ate my cake?\n"

+                        + "</body>\r\n"

+                        + "</message>\r\n";

+        

+        parser.parse(new ByteArrayInputStream(msg.getBytes()));

+        String result = handler.sb.toString();

+        

+        assertEquals(expected, result);

+    }

+    

+    protected String decode(ByteSequence byteSequence) {

+        return ContentUtil.decode(byteSequence);

+    }

+    

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamTokenMessageRfc822Test.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamTokenMessageRfc822Test.java
new file mode 100644
index 0000000..338375e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeStreamTokenMessageRfc822Test.java
@@ -0,0 +1,101 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.ExampleMail;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+import org.apache.james.mime4j.parser.RecursionMode;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class MimeStreamTokenMessageRfc822Test extends TestCase {
+
+    MimeTokenStream stream;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        stream = new MimeTokenStream();
+        stream.parse(new ByteArrayInputStream(ExampleMail.MIME_RFC822_SIMPLE_BYTES));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testShouldParseMessageRFC822CorrectWithDefaultConfiguration() throws Exception {
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_START_MESSAGE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    public void testShouldParseMessageRFC822CorrectWithNoRecurse() throws Exception {
+        stream.setRecursionMode(RecursionMode.M_NO_RECURSE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    public void testShouldParseMessageRFC822CorrectWithFlat() throws Exception {
+        stream.setRecursionMode(RecursionMode.M_FLAT);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    private void nextIs(int state) throws Exception {
+        assertEquals(MimeTokenStream.stateToString(state), MimeTokenStream.stateToString(stream.next()));
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenEmbeddedMessageTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenEmbeddedMessageTest.java
new file mode 100644
index 0000000..2e7b6b8
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenEmbeddedMessageTest.java
@@ -0,0 +1,216 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.ExampleMail;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class MimeTokenEmbeddedMessageTest extends TestCase {
+    
+    MimeTokenStream stream;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        stream = new MimeTokenStream();
+        InputStream in = new ByteArrayInputStream(ExampleMail.MIME_MULTIPART_EMBEDDED_MESSAGES_BYTES);
+        stream.parse(in);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testWhenRecurseShouldVisitInnerMailsAndInnerMultiparts() throws Exception {
+        stream.setRecursionMode(MimeTokenStream.M_RECURSE);
+
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        
+        nextIs(MimeTokenStream.T_PREAMBLE);
+
+        // PART ONE
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream("Rhubarb!\r\n");
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        
+        // PART TWO
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream("987654321AHPLA\r\n");
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        
+        // PART THREE
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_START_MESSAGE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream("Custard!\r\n");
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream("CUSTARDCUSTARDCUSTARD\r\n");
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        nextIs(MimeTokenStream.T_EPILOGUE);
+        nextIs(MimeTokenStream.T_END_MULTIPART);   
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        
+        // PART FOUR
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        checkInputStream(ExampleMail.MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MULTIPART_MIXED);
+        nextIs(MimeTokenStream.T_END_MULTIPART);
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        nextIs(MimeTokenStream.T_EPILOGUE);
+        nextIs(MimeTokenStream.T_END_MULTIPART);
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    
+    public void testWhenFlatAtStartShouldIgnoreMultipartStructure() throws Exception {
+        stream.setRecursionMode(MimeTokenStream.M_FLAT);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_BODY);
+        
+        checkInputStream(ExampleMail.MIME_MULTIPART_EMBEDDED_MESSAGES_BODY);
+        
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+    }
+    
+    public void testWhenFlatShouldIgnoreInnerMailsAndInnerMultiparts() throws Exception {
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        
+        stream.setRecursionMode(MimeTokenStream.M_FLAT);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+
+        // PART ONE
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream("Rhubarb!\r\n");
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        
+        // PART TWO
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream("987654321AHPLA\r\n");
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        
+        // PART THREE
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream(ExampleMail.MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MAIL);
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        
+        // PART FOUR
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        checkInputStream(ExampleMail.MIME_MULTIPART_EMBEDDED_MESSAGES_INNER_MULTIPART_MIXED);
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        nextIs(MimeTokenStream.T_EPILOGUE);
+        nextIs(MimeTokenStream.T_END_MULTIPART);
+    }
+    
+    private void checkInputStream(String expected) throws Exception {
+        InputStream inputStream = stream.getInputStream();
+        int next = inputStream.read();
+        int i=0;
+        while (next != -1) {
+            assertEquals("@" + i, expected.charAt(i++), (char) next);
+            next = inputStream.read();
+        }
+        assertEquals(expected.length(), i);
+    }
+    
+    private void nextIs(int state) throws Exception {
+        assertEquals(MimeTokenStream.stateToString(state), MimeTokenStream.stateToString(stream.next()));
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenNoRecurseTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenNoRecurseTest.java
new file mode 100644
index 0000000..bf8ff5e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenNoRecurseTest.java
@@ -0,0 +1,222 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class MimeTokenNoRecurseTest extends TestCase {
+
+    private static final String INNER_MAIL = "From: Timothy Tayler <tim@example.org>\r\n" +
+                "To: Joshua Tetley <joshua@example.org>\r\n" +
+                "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+                "Subject: Multipart Without RFC822 Part\r\n" +
+                "Content-Type: multipart/mixed;boundary=42\r\n\r\n" +
+                "--42\r\n" +
+                "Content-Type:text/plain; charset=US-ASCII\r\n\r\n" +
+                "First part of this mail\r\n" +
+                "--42\r\n" +
+                "Content-Type:text/plain; charset=US-ASCII\r\n\r\n" +
+                "Second part of this mail\r\n" +
+                "--42--\r\n";
+
+    private static final String MAIL_WITH_RFC822_PART = "MIME-Version: 1.0\r\n" +
+            "From: Timothy Tayler <tim@example.org>\r\n" +
+            "To: Joshua Tetley <joshua@example.org>\r\n" +
+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+            "Subject: Multipart With RFC822 Part\r\n" +
+            "Content-Type: multipart/mixed;boundary=1729\r\n\r\n" +
+            "A short premable\r\n" +
+            "--1729\r\n\r\n" +
+            "First part has no headers\r\n" +
+            "--1729\r\n" +
+            "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+            "Second part is plain text\r\n" +
+            "--1729\r\n" +
+            "Content-Type: message/rfc822\r\n\r\n" +
+            INNER_MAIL +
+            "--1729\r\n" +
+            "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+            "Last part is plain text\r\n" +
+            "--1729--\r\n" +
+            "The End";
+    
+    MimeTokenStream stream;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        stream = new MimeTokenStream();
+        byte[] bytes = CharsetUtil.US_ASCII.encode(MAIL_WITH_RFC822_PART).array();
+        InputStream in = new ByteArrayInputStream(bytes);
+        stream.parse(in);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testWhenRecurseShouldRecurseInnerMail() throws Exception {
+        stream.setRecursionMode(MimeTokenStream.M_RECURSE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+        nextShouldBeStandardPart(false);
+        
+        nextShouldBeStandardPart(true);
+        
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_START_MESSAGE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+        nextShouldBeStandardPart(true);
+        nextShouldBeStandardPart(true);
+        nextIs(MimeTokenStream.T_EPILOGUE);
+        nextIs(MimeTokenStream.T_END_MULTIPART);
+        nextIs(MimeTokenStream.T_END_MESSAGE);
+        nextIs(MimeTokenStream.T_END_BODYPART);
+        nextShouldBeStandardPart(true);
+        nextIs(MimeTokenStream.T_EPILOGUE);
+        nextIs(MimeTokenStream.T_END_MULTIPART);
+    }
+    
+
+    public void testWhenRecurseShouldTreatInnerMailAsAnyOtherPart() throws Exception {
+        stream.setRecursionMode(MimeTokenStream.M_NO_RECURSE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+        nextShouldBeStandardPart(false);
+        
+        nextShouldBeStandardPart(true);
+        nextShouldBeStandardPart(true);
+        nextShouldBeStandardPart(true);
+        nextIs(MimeTokenStream.T_EPILOGUE);
+        nextIs(MimeTokenStream.T_END_MULTIPART);
+    }
+    
+    public void testWhenNoRecurseInputStreamShouldContainInnerMail() throws Exception {
+        stream.setRecursionMode(MimeTokenStream.M_NO_RECURSE);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+        nextShouldBeStandardPart(false);
+        
+        nextShouldBeStandardPart(true);
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        InputStream inputStream = stream.getInputStream();
+        int next = inputStream.read();
+        int i=0;
+        while (next != -1) {
+            assertEquals("@" + i, INNER_MAIL.charAt(i++), (char) next);
+            next = inputStream.read();
+        }
+        assertEquals(INNER_MAIL.length()-2, i);
+    }
+    
+    public void testSetNoRecurseSoInputStreamShouldContainInnerMail() throws Exception {
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        
+        nextIs(MimeTokenStream.T_START_MULTIPART);
+        nextIs(MimeTokenStream.T_PREAMBLE);
+        nextShouldBeStandardPart(false);
+        
+        nextShouldBeStandardPart(true);
+        stream.setRecursionMode(MimeTokenStream.M_NO_RECURSE);
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        nextIs(MimeTokenStream.T_FIELD);
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        InputStream inputStream = stream.getInputStream();
+        int next = inputStream.read();
+        int i=0;
+        while (next != -1) {
+            assertEquals("@" + i, INNER_MAIL.charAt(i++), (char) next);
+            next = inputStream.read();
+        }
+        assertEquals(INNER_MAIL.length()-2, i);
+    }
+
+    private void nextShouldBeStandardPart(boolean withHeader) throws Exception {
+        nextIs(MimeTokenStream.T_START_BODYPART);
+        nextIs(MimeTokenStream.T_START_HEADER);
+        if (withHeader) {
+            nextIs(MimeTokenStream.T_FIELD);
+        }
+        nextIs(MimeTokenStream.T_END_HEADER);
+        nextIs(MimeTokenStream.T_BODY);
+        nextIs(MimeTokenStream.T_END_BODYPART);
+    }
+    
+    private void nextIs(int state) throws Exception {
+        assertEquals(MimeTokenStream.stateToString(state), MimeTokenStream.stateToString(stream.next()));
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamBodyDescriptorTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamBodyDescriptorTest.java
new file mode 100644
index 0000000..f1b4e8d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamBodyDescriptorTest.java
@@ -0,0 +1,97 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.ExampleMail;
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class MimeTokenStreamBodyDescriptorTest extends TestCase {
+
+    MimeTokenStream parser;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        parser = new MimeTokenStream();
+        parser.parse(new ByteArrayInputStream(ExampleMail.MIME_MULTIPART_ALTERNATIVE_BYTES));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testShouldReturnValidDescriptorForPreamble() throws Exception {
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_MULTIPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_PREAMBLE), MimeTokenStream.stateToString(parser.next()));
+        BodyDescriptor descriptor = parser.getBodyDescriptor();
+        assertNotNull(descriptor);
+        assertEquals("1729", descriptor.getBoundary());
+        assertEquals( "multipart/alternative", descriptor.getMimeType());
+    }
+    
+    public void testShouldReturnValidDescriptorForEpilogue() throws Exception {
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_MULTIPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_PREAMBLE), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_BODYPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_BODYPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_BODYPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_BODYPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_BODYPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_BODYPART), MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_EPILOGUE), MimeTokenStream.stateToString(parser.next()));
+
+        BodyDescriptor descriptor = parser.getBodyDescriptor();
+        assertNotNull(descriptor);
+        assertEquals("1729", descriptor.getBoundary());
+        assertEquals( "multipart/alternative", descriptor.getMimeType());
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamReaderTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamReaderTest.java
new file mode 100644
index 0000000..41ba93a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamReaderTest.java
@@ -0,0 +1,140 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.ExampleMail;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+import junit.framework.TestCase;
+
+public class MimeTokenStreamReaderTest extends TestCase {
+    
+    MimeTokenStream parser;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        parser = new MimeTokenStream();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testShouldReadSimpleBody() throws Exception {
+        byte[] bytes = ExampleMail.RFC822_SIMPLE_BYTES;
+        String body = ExampleMail.RFC822_SIMPLE_BODY;
+        checkSimpleMail(bytes, body, 4);
+    }
+
+    public void testShouldReadOnePartMimeASCIIBody() throws Exception {
+        byte[] bytes = ExampleMail.ONE_PART_MIME_ASCII_BYTES;
+        String body = ExampleMail.ONE_PART_MIME_ASCII_BODY;
+        checkSimpleMail(bytes, body, 11);
+    }
+
+    public void testShouldReadOnePartMime8859Body() throws Exception {
+        byte[] bytes = ExampleMail.ONE_PART_MIME_8859_BYTES;
+        String body = ExampleMail.ONE_PART_MIME_8859_BODY;
+        checkSimpleMail(bytes, body, 13);
+    }
+    
+    public void testShouldReadOnePartMimeBase64ASCIIBody() throws Exception {
+        byte[] bytes = ExampleMail.ONE_PART_MIME_BASE64_ASCII_BYTES;
+        String body = ExampleMail.ONE_PART_MIME_BASE64_ASCII_BODY;
+        checkSimpleMail(bytes, body, 11);
+    }
+    
+    public void testShouldReadOnePartMimeBase64Latin1Body() throws Exception {
+        byte[] bytes = ExampleMail.ONE_PART_MIME_BASE64_LATIN1_BYTES;
+        String body = ExampleMail.ONE_PART_MIME_BASE64_LATIN1_BODY;
+        checkSimpleMail(bytes, body, 11);
+    }
+    
+    public void testShouldReadOnePartMimeQuotedPrintable() throws Exception {
+        byte[] bytes = ExampleMail.ONE_PART_MIME_QUOTED_PRINTABLE_ASCII_BYTES;
+        String body = ExampleMail.ONE_PART_MIME_QUOTED_PRINTABLE_ASCII_BODY;
+        checkSimpleMail(bytes, body, 11);
+    }
+    
+    public void testShouldReadPartBodies() throws IOException, MimeException {
+        InputStream in = new ByteArrayInputStream(ExampleMail.MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BYTES);
+        parser.parse(in);
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER),MimeTokenStream.stateToString(parser.next()));
+        for (int i=0;i<5;i++) {
+            assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        }
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_MULTIPART),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_PREAMBLE),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_BODYPART),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY),MimeTokenStream.stateToString(parser.next()));
+        checkBody(ExampleMail.MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_7BIT);
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_BODYPART),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_BODYPART),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY),MimeTokenStream.stateToString(parser.next()));
+        checkBody(ExampleMail.MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_QUOTED_PRINTABLE);
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_BODYPART),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_BODYPART),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY),MimeTokenStream.stateToString(parser.next()));
+        checkBody(ExampleMail.MIME_MIXED_MULTIPART_VARIOUS_ENCODINGS_BASE64);
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_BODYPART),MimeTokenStream.stateToString(parser.next()));
+
+        
+    }
+    
+    private void checkSimpleMail(byte[] bytes, String body, int fields) throws IOException, MimeException {
+        InputStream in = new ByteArrayInputStream(bytes);
+        parser.parse(in);
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_START_HEADER),MimeTokenStream.stateToString(parser.next()));
+        for (int i=0;i<fields;i++) {
+            assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_FIELD),MimeTokenStream.stateToString(parser.next()));
+        }
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_END_HEADER),MimeTokenStream.stateToString(parser.next()));
+        assertEquals(MimeTokenStream.stateToString(MimeTokenStream.T_BODY),MimeTokenStream.stateToString(parser.next()));
+        checkBody(body);
+    }
+
+    private void checkBody(String body) throws IOException {
+        Reader reader = parser.getReader();
+        assertNotNull(reader);
+        assertEquals(body, IOUtils.toString(reader));
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamTest.java
new file mode 100644
index 0000000..53a0009
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MimeTokenStreamTest.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.ExampleMail;
+import org.apache.james.mime4j.parser.EntityStates;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+import org.apache.james.mime4j.parser.RecursionMode;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class MimeTokenStreamTest extends TestCase {
+
+    MimeTokenStream stream;
+    
+    @Override
+    public void setUp() throws Exception {
+        stream = new MimeTokenStream();
+    }
+    
+    public void testSetRecursionModeBeforeParse() throws Exception {
+        stream.setRecursionMode(RecursionMode.M_NO_RECURSE);
+        stream.parse(new ByteArrayInputStream(ExampleMail.MAIL_WITH_RFC822_PART_BYTES));
+        checkNextIs(EntityStates.T_START_HEADER);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_END_HEADER);
+        checkNextIs(EntityStates.T_START_MULTIPART);
+        checkNextIs(EntityStates.T_PREAMBLE);
+        checkNextIs(EntityStates.T_START_BODYPART);
+        checkNextIs(EntityStates.T_START_HEADER);
+        checkNextIs(EntityStates.T_END_HEADER);
+        checkNextIs(EntityStates.T_BODY);
+        checkNextIs(EntityStates.T_END_BODYPART);
+        checkNextIs(EntityStates.T_START_BODYPART);
+        checkNextIs(EntityStates.T_START_HEADER);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_END_HEADER);
+        checkNextIs(EntityStates.T_BODY);
+        checkNextIs(EntityStates.T_END_BODYPART);
+        checkNextIs(EntityStates.T_START_BODYPART);
+        checkNextIs(EntityStates.T_START_HEADER);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_END_HEADER);
+        checkNextIs(EntityStates.T_BODY);
+        checkNextIs(EntityStates.T_END_BODYPART);
+        checkNextIs(EntityStates.T_START_BODYPART);
+        checkNextIs(EntityStates.T_START_HEADER);
+        checkNextIs(EntityStates.T_FIELD);
+        checkNextIs(EntityStates.T_END_HEADER);
+        checkNextIs(EntityStates.T_BODY);
+        checkNextIs(EntityStates.T_END_BODYPART);
+        checkNextIs(EntityStates.T_EPILOGUE);
+        checkNextIs(EntityStates.T_END_MULTIPART);
+        checkNextIs(EntityStates.T_END_MESSAGE);
+        checkNextIs(EntityStates.T_END_OF_STREAM);
+    }
+    
+    private void checkNextIs(int expected) throws Exception {
+        assertEquals(MimeTokenStream.stateToString(expected), MimeTokenStream.stateToString(stream.next()));        
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MultipartStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MultipartStreamTest.java
new file mode 100644
index 0000000..1bb6850
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MultipartStreamTest.java
@@ -0,0 +1,148 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class MultipartStreamTest extends TestCase {
+
+    private static final Charset US_ASCII = CharsetUtil.US_ASCII;
+    
+    private static final String BODY = "A Preamble\r\n" +
+                "--1729\r\n\r\n" +
+                "Simple plain text\r\n" +
+                "--1729\r\n" +
+                "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+                "Some more text\r\n" +
+                "--1729--\r\n";
+    public static final String MESSAGE = "To: Road Runner <runner@example.org>\r\n" +
+            "From: Wile E. Cayote <wile@example.org>\r\n" +
+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+            "Subject: Mail\r\n" +
+            "Content-Type: multipart/mixed;boundary=1729\r\n\r\n" +
+            BODY;
+    
+    public static final String COMPLEX_MESSAGE = "To: Wile E. Cayote <wile@example.org>\r\n" +
+    "From: Road Runner <runner@example.org>\r\n" +
+    "Date: Tue, 19 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+    "Subject: Mail\r\n" +
+    "Content-Type: multipart/mixed;boundary=42\r\n\r\n" +
+    "A little preamble\r\n" +
+    "--42\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+    "Rhubard!\r\n" +
+    "--42\r\n" +
+    "Content-Type: message/rfc822\r\n\r\n" +
+    MESSAGE +
+    "\r\n" +
+    "--42\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+    "Custard!" +
+    "\r\n" +
+    "--42--\r\n";
+    
+    MimeTokenStream parser;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        parser = new MimeTokenStream();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testShouldSupplyInputStreamForSimpleBody() throws Exception {
+        parser.parse(new ByteArrayInputStream(US_ASCII.encode(MESSAGE).array()));
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        InputStream out = parser.getInputStream();
+        assertEquals(BODY, IOUtils.toString(out, "us-ascii"));
+        checkState(MimeTokenStream.T_END_MULTIPART);
+    }
+    
+    public void testInputStreamShouldReadOnlyMessage() throws Exception {
+        parser.parse(new ByteArrayInputStream(US_ASCII.encode(COMPLEX_MESSAGE).array()));
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MESSAGE);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        InputStream out = parser.getInputStream();
+        assertEquals(BODY, IOUtils.toString(out, "us-ascii"));
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+
+    private void checkState(final int state) throws IOException, MimeException {
+        assertEquals(MimeTokenStream.stateToString(state), MimeTokenStream.stateToString(parser.next()));
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MultipartTokensTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MultipartTokensTest.java
new file mode 100644
index 0000000..8c1ed85
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/MultipartTokensTest.java
@@ -0,0 +1,301 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.util.CharsetUtil;
+
+public class MultipartTokensTest extends TestCase {
+
+    private static final Charset US_ASCII = CharsetUtil.US_ASCII;
+    
+    private static final String BODY = "A Preamble\r\n" +
+                "--1729\r\n\r\n" +
+                "Simple plain text\r\n" +
+                "--1729\r\n" +
+                "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+                "Some more text\r\n" +
+                "--1729--\r\n";
+    public static final String MESSAGE = "To: Road Runner <runner@example.org>\r\n" +
+            "From: Wile E. Cayote <wile@example.org>\r\n" +
+            "Date: Tue, 12 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+            "Subject: Mail\r\n" +
+            "Content-Type: multipart/mixed;boundary=1729\r\n\r\n" +
+            BODY;
+    
+    public static final String COMPLEX_MESSAGE = "To: Wile E. Cayote <wile@example.org>\r\n" +
+    "From: Road Runner <runner@example.org>\r\n" +
+    "Date: Tue, 19 Feb 2008 17:34:09 +0000 (GMT)\r\n" +
+    "Subject: Mail\r\n" +
+    "Content-Type: multipart/mixed;boundary=42\r\n\r\n" +
+    "A little preamble\r\n" +
+    "--42\r\n" +
+    "Content-Type: text/plain; charset=US-ASCII\r\n\r\n" +
+    "Rhubard!\r\n" +
+    "--42\r\n" +
+    "Content-Type: message/rfc822\r\n\r\n" +
+    MESSAGE +
+    "\r\n" +
+    "--42\r\n" +
+    "\r\n" +
+    "Custard!" +
+    "\r\n" +
+    "--42--\r\n";
+    
+    public static final String COMPLEX_QP_MESSAGE = 
+        "Content-Transfer-Encoding: quoted-printable\r\n" +
+        "Content-Type: message/rfc822; charset=us-ascii\r\n" +
+        "\r\n" +
+        "Subject: The subject\r\n" +
+        "Content-Type: multipart/alternative;\r\n" +
+        "        boundary=3D=22----=3DNextPart=22\r\n" +
+        "\r\n" +
+        "This is a multi-part message in MIME format.\r\n" +
+        "\r\n" +
+        "------=3DNextPart\r\n" +
+        "Content-Type: text/plain;\r\n" +
+        "        charset=3D=22iso-8859-1=22\r\n" +
+        "\r\n" +
+        "Some text\r\n" +
+        "\r\n" +
+        "------=3DNextPart\r\n" +
+        "Content-Type: text/html;\r\n" +
+        "        charset=3D=22iso-8859-1=22\r\n" +
+        "\r\n" +
+        "<HTML><BODY>=3D Some HTML =3D</BODY></HTML>\r\n" +
+        "------=3DNextPart--\r\n" +
+        "\r\n" +
+        "\r\n";
+    
+    MimeTokenStream parser;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        parser = new MimeTokenStream();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testShouldParseSimpleMessage() throws Exception {
+        parser.parse(new ByteArrayInputStream(US_ASCII.encode(MESSAGE).array()));
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    public void testShouldParseMoreComplexMessage() throws Exception {
+        String message = 
+            "Content-Type: multipart/alternative; boundary=\"outer-boundary\"\r\n" +
+            "\r\n" +
+            "--outer-boundary\r\n" +
+            "Content-Type: multipart/alternative; boundary=\"inner-boundary\"\r\n" +
+            "\r\n" +
+            "--inner-boundary\r\n" +
+            "Content-Type: text/plain\r\n" +
+            "\r\n" +
+            "Some text\r\n" +
+            "--inner-boundary--\r\n" +
+            "\r\n" +
+            "foo\r\n" +
+            "--outer-boundary--\r\n";
+        
+        parser.parse(new ByteArrayInputStream(US_ASCII.encode(message).array()));
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    public void testShouldParseMessageWithEmbeddedMessage() throws Exception {
+        parser.parse(new ByteArrayInputStream(US_ASCII.encode(COMPLEX_MESSAGE).array()));
+        checkState(MimeTokenStream.T_START_HEADER);
+            checkState(MimeTokenStream.T_FIELD);
+            checkState(MimeTokenStream.T_FIELD);
+            checkState(MimeTokenStream.T_FIELD);
+            checkState(MimeTokenStream.T_FIELD);
+            checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+            checkState(MimeTokenStream.T_PREAMBLE);
+            checkState(MimeTokenStream.T_START_BODYPART);
+                checkState(MimeTokenStream.T_START_HEADER);
+                    checkState(MimeTokenStream.T_FIELD);
+                checkState(MimeTokenStream.T_END_HEADER);
+                checkState(MimeTokenStream.T_BODY);
+            checkState(MimeTokenStream.T_END_BODYPART);
+            checkState(MimeTokenStream.T_START_BODYPART);
+                checkState(MimeTokenStream.T_START_HEADER);
+                    checkState(MimeTokenStream.T_FIELD);
+                checkState(MimeTokenStream.T_END_HEADER);
+                checkState(MimeTokenStream.T_START_MESSAGE);
+                    checkState(MimeTokenStream.T_START_HEADER);
+                        checkState(MimeTokenStream.T_FIELD);
+                        checkState(MimeTokenStream.T_FIELD);
+                        checkState(MimeTokenStream.T_FIELD);
+                        checkState(MimeTokenStream.T_FIELD);
+                        checkState(MimeTokenStream.T_FIELD);
+                    checkState(MimeTokenStream.T_END_HEADER);
+                    checkState(MimeTokenStream.T_START_MULTIPART);
+                        checkState(MimeTokenStream.T_PREAMBLE);
+                        checkState(MimeTokenStream.T_START_BODYPART);
+                            checkState(MimeTokenStream.T_START_HEADER);
+                            checkState(MimeTokenStream.T_END_HEADER);   
+                            checkState(MimeTokenStream.T_BODY);
+                        checkState(MimeTokenStream.T_END_BODYPART);
+                        checkState(MimeTokenStream.T_START_BODYPART);
+                            checkState(MimeTokenStream.T_START_HEADER);
+                                checkState(MimeTokenStream.T_FIELD);
+                            checkState(MimeTokenStream.T_END_HEADER);
+                            checkState(MimeTokenStream.T_BODY);
+                        checkState(MimeTokenStream.T_END_BODYPART);
+                        checkState(MimeTokenStream.T_EPILOGUE);
+                    checkState(MimeTokenStream.T_END_MULTIPART);
+                checkState(MimeTokenStream.T_END_MESSAGE);
+            checkState(MimeTokenStream.T_END_BODYPART);
+            checkState(MimeTokenStream.T_START_BODYPART);
+                checkState(MimeTokenStream.T_START_HEADER);
+                checkState(MimeTokenStream.T_END_HEADER);
+                checkState(MimeTokenStream.T_BODY);
+            checkState(MimeTokenStream.T_END_BODYPART);
+            checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+
+    public void testShouldParseMessagesWithEmbeddedQuotedPrintableEncodedMessage() throws Exception {
+        parser.parse(new ByteArrayInputStream(US_ASCII.encode(COMPLEX_QP_MESSAGE).array()));
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MESSAGE);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        assertEquals("text/plain", parser.getBodyDescriptor().getMimeType());
+        assertEquals("iso-8859-1", parser.getBodyDescriptor().getCharset());
+        assertEquals("Some text\r\n", 
+                IOUtils.toString(parser.getInputStream()));
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        assertEquals("text/html", parser.getBodyDescriptor().getMimeType());
+        assertEquals("iso-8859-1", parser.getBodyDescriptor().getCharset());
+        assertEquals("<HTML><BODY>= Some HTML =</BODY></HTML>", 
+                IOUtils.toString(parser.getInputStream()));
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    public void testMultipartMessageWithoutHeader() throws Exception {
+        parser.parseHeadless(new ByteArrayInputStream(US_ASCII.encode(BODY).array()), 
+                "multipart/mixed;boundary=1729");
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_START_MULTIPART);
+        checkState(MimeTokenStream.T_PREAMBLE);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_START_BODYPART);
+        checkState(MimeTokenStream.T_START_HEADER);
+        checkState(MimeTokenStream.T_FIELD);
+        checkState(MimeTokenStream.T_END_HEADER);
+        checkState(MimeTokenStream.T_BODY);
+        checkState(MimeTokenStream.T_END_BODYPART);
+        checkState(MimeTokenStream.T_EPILOGUE);
+        checkState(MimeTokenStream.T_END_MULTIPART);
+        checkState(MimeTokenStream.T_END_MESSAGE);
+        checkState(MimeTokenStream.T_END_OF_STREAM);
+    }
+    
+    private void checkState(final int state) throws IOException, MimeException {
+        assertEquals(MimeTokenStream.stateToString(state), MimeTokenStream.stateToString(parser.next()));
+    }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/StrictMimeTokenStreamTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/StrictMimeTokenStreamTest.java
new file mode 100644
index 0000000..1cd49c0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/StrictMimeTokenStreamTest.java
@@ -0,0 +1,62 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.parser.Event;
+import org.apache.james.mime4j.parser.MimeParseEventException;
+import org.apache.james.mime4j.parser.MimeTokenStream;
+
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+public class StrictMimeTokenStreamTest extends TestCase {
+    
+    private static final String HEADER_ONLY = "From: foo@abr.com\r\nSubject: A subject\r\n";
+    private static final String CORRECT_HEADERS = HEADER_ONLY + "\r\n";
+    
+    public void testUnexpectedEndOfHeaders() throws Exception {
+        
+        MimeTokenStream parser = MimeTokenStream.createStrictValidationStream();
+        
+        parser.parse(new ByteArrayInputStream(HEADER_ONLY.getBytes()));
+        
+        assertEquals("Headers start", MimeTokenStream.T_START_HEADER, parser.next());
+        assertEquals("Field", MimeTokenStream.T_FIELD, parser.next());
+        try {
+            parser.next();
+            fail("Expected exception to be thrown");
+        } catch (MimeParseEventException e) {
+            assertEquals("Premature end of headers", Event.HEADERS_PREMATURE_END, e.getEvent());
+        }
+     }
+    
+    public void testCorrectEndOfHeaders() throws Exception {
+        
+        MimeTokenStream parser = MimeTokenStream.createStrictValidationStream();
+        
+        parser.parse(new ByteArrayInputStream(CORRECT_HEADERS.getBytes()));
+        
+        assertEquals("Headers start", MimeTokenStream.T_START_HEADER, parser.next());
+        assertEquals("From header", MimeTokenStream.T_FIELD, parser.next());
+        assertEquals("Subject header", MimeTokenStream.T_FIELD, parser.next());
+        assertEquals("End message", MimeTokenStream.T_END_HEADER, parser.next());
+     }
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/TestHandler.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/TestHandler.java
new file mode 100644
index 0000000..402f700
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/parser/TestHandler.java
@@ -0,0 +1,112 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.parser;
+
+import org.apache.james.mime4j.descriptor.BodyDescriptor;
+import org.apache.james.mime4j.parser.ContentHandler;
+import org.apache.james.mime4j.util.ContentUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Helper class to run comparison of parsed results
+ */
+class TestHandler implements ContentHandler {
+    StringBuilder sb = new StringBuilder();
+
+    private String escape(char c) {
+        if (c == '&') {
+            return "&amp;";
+        }
+        if (c == '>') {
+            return "&gt;";
+        }
+        if (c == '<') {
+            return "&lt;";
+        }
+        return "" + c;
+    }
+    
+    private String escape(String s) {
+        s = s.replaceAll("&", "&amp;");
+        s = s.replaceAll(">", "&gt;");
+        s = s.replaceAll("<", "&lt;");
+        return s;
+    }
+    
+    public void epilogue(InputStream is) throws IOException {
+        sb.append("<epilogue>\r\n");
+        int b = 0;
+        while ((b = is.read()) != -1) {
+            sb.append(escape((char) b));
+        }
+        sb.append("</epilogue>\r\n");
+    }
+    public void preamble(InputStream is) throws IOException {
+        sb.append("<preamble>\r\n");
+        int b = 0;
+        while ((b = is.read()) != -1) {
+            sb.append(escape((char) b));
+        }
+        sb.append("</preamble>\r\n");
+    }
+    public void startMultipart(BodyDescriptor bd) {
+        sb.append("<multipart>\r\n");
+    }
+    public void body(BodyDescriptor bd, InputStream is) throws IOException {
+        sb.append("<body>\r\n");
+        int b = 0;
+        while ((b = is.read()) != -1) {
+            sb.append(escape((char) b));
+        }
+        sb.append("</body>\r\n");
+    }
+    public void endMultipart() {
+        sb.append("</multipart>\r\n");
+    }
+    public void startBodyPart() {
+        sb.append("<body-part>\r\n");
+    }
+    public void endBodyPart() {
+        sb.append("</body-part>\r\n");
+    }
+    public void startHeader() {
+        sb.append("<header>\r\n");
+    }
+    public void field(Field field) {
+        sb.append("<field>\r\n"
+                + escape(ContentUtil.decode(field.getRaw()))
+                + "</field>\r\n");
+    }
+    public void endHeader() {
+        sb.append("</header>\r\n");
+    }
+    public void startMessage() {
+        sb.append("<message>\r\n");
+    }
+    public void endMessage() {
+        sb.append("</message>\r\n");
+    }
+
+    public void raw(InputStream is) throws IOException {
+        MimeStreamParserExampleMessagesTest.fail("raw should never be called");
+    }
+}
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/DefaultStorageProviderTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/DefaultStorageProviderTest.java
new file mode 100644
index 0000000..3c1b618
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/DefaultStorageProviderTest.java
@@ -0,0 +1,59 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import junit.framework.TestCase;
+
+public class DefaultStorageProviderTest extends TestCase {
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.getProperties().remove(
+                DefaultStorageProvider.DEFAULT_STORAGE_PROVIDER_PROPERTY);
+        DefaultStorageProvider.reset();
+    }
+
+    public void testDefaultInstance() throws Exception {
+        System.getProperties().remove(
+                DefaultStorageProvider.DEFAULT_STORAGE_PROVIDER_PROPERTY);
+        DefaultStorageProvider.reset();
+
+        StorageProvider instance = DefaultStorageProvider.getInstance();
+        assertTrue(instance instanceof ThresholdStorageProvider);
+    }
+
+    public void testSetDefaultProperty() throws Exception {
+        System.setProperty(
+                DefaultStorageProvider.DEFAULT_STORAGE_PROVIDER_PROPERTY,
+                MemoryStorageProvider.class.getName());
+        DefaultStorageProvider.reset();
+
+        StorageProvider instance = DefaultStorageProvider.getInstance();
+        assertTrue(instance instanceof MemoryStorageProvider);
+    }
+
+    public void testSetter() throws Exception {
+        StorageProvider instance = new MemoryStorageProvider();
+
+        DefaultStorageProvider.setInstance(instance);
+        assertSame(instance, DefaultStorageProvider.getInstance());
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/MultiReferenceStorageTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/MultiReferenceStorageTest.java
new file mode 100644
index 0000000..6900b79
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/MultiReferenceStorageTest.java
@@ -0,0 +1,107 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class MultiReferenceStorageTest extends TestCase {
+
+    public void testForwardsGetInputStream() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+
+        assertEquals(ByteArrayInputStream.class, multiReferenceStorage
+                .getInputStream().getClass());
+    }
+
+    public void testSingleReference() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+
+        assertFalse(storage.deleted);
+
+        multiReferenceStorage.delete();
+        assertTrue(storage.deleted);
+    }
+
+    public void testMultiReference() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+
+        multiReferenceStorage.addReference();
+
+        multiReferenceStorage.delete();
+        assertFalse(storage.deleted);
+
+        multiReferenceStorage.delete();
+        assertTrue(storage.deleted);
+    }
+
+    public void testGetInputStreamOnDeleted() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+
+        multiReferenceStorage.delete();
+
+        try {
+            multiReferenceStorage.getInputStream();
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    public void testAddReferenceOnDeleted() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new MultiReferenceStorage(
+                storage);
+
+        multiReferenceStorage.delete();
+
+        try {
+            multiReferenceStorage.addReference();
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    private static final class DummyStorage implements Storage {
+        public boolean deleted = false;
+
+        public InputStream getInputStream() throws IOException {
+            if (deleted)
+                throw new IllegalStateException("deleted");
+
+            return new ByteArrayInputStream("dummy".getBytes());
+        }
+
+        public void delete() {
+            deleted = true;
+        }
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/StorageProviderTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/StorageProviderTest.java
new file mode 100644
index 0000000..58d3e94
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/storage/StorageProviderTest.java
@@ -0,0 +1,147 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.storage;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.james.mime4j.codec.CodecUtil;
+
+import junit.framework.TestCase;
+
+public class StorageProviderTest extends TestCase {
+
+    public void testMemoryStorageProvider() throws Exception {
+        StorageProvider provider = new MemoryStorageProvider();
+
+        testReadWrite(provider, 0);
+        testReadWrite(provider, 1);
+        testReadWrite(provider, 1024);
+        testReadWrite(provider, 20000);
+
+        testDelete(provider);
+    }
+
+    public void testTempFileStorageProvider() throws Exception {
+        StorageProvider provider = new TempFileStorageProvider();
+
+        testReadWrite(provider, 0);
+        testReadWrite(provider, 1);
+        testReadWrite(provider, 1024);
+        testReadWrite(provider, 20000);
+
+        testDelete(provider);
+    }
+
+    public void testThresholdStorageProvider() throws Exception {
+        final int threshold = 5000;
+        StorageProvider backend = new TempFileStorageProvider();
+        StorageProvider provider = new ThresholdStorageProvider(backend,
+                threshold);
+
+        testReadWrite(provider, 0);
+        testReadWrite(provider, 1);
+        testReadWrite(provider, threshold - 1);
+        testReadWrite(provider, threshold);
+        testReadWrite(provider, threshold + 1);
+        testReadWrite(provider, 2 * threshold);
+        testReadWrite(provider, 10 * threshold);
+
+        testDelete(provider);
+    }
+
+    public void testCipherStorageProvider() throws Exception {
+        StorageProvider backend = new TempFileStorageProvider();
+        StorageProvider provider = new CipherStorageProvider(backend);
+
+        testReadWrite(provider, 0);
+        testReadWrite(provider, 1);
+        testReadWrite(provider, 1024);
+        testReadWrite(provider, 20000);
+
+        testDelete(provider);
+    }
+
+    private void testReadWrite(StorageProvider provider, int size)
+            throws IOException {
+        testStore(provider, size);
+        testCreateStorageOutputStream(provider, size);
+    }
+
+    private void testStore(StorageProvider provider, int size)
+            throws IOException {
+        byte[] data = createData(size);
+        assertEquals(size, data.length);
+
+        Storage storage = provider.store(new ByteArrayInputStream(data));
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        CodecUtil.copy(storage.getInputStream(), baos);
+        verifyData(data, baos.toByteArray());
+    }
+
+    private void testCreateStorageOutputStream(StorageProvider provider,
+            int size) throws IOException {
+        byte[] data = createData(size);
+        assertEquals(size, data.length);
+
+        StorageOutputStream out = provider.createStorageOutputStream();
+        CodecUtil.copy(new ByteArrayInputStream(data), out);
+        Storage storage = out.toStorage();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        CodecUtil.copy(storage.getInputStream(), baos);
+        verifyData(data, baos.toByteArray());
+    }
+
+    private void verifyData(byte[] expected, byte[] actual) {
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+
+    private byte[] createData(int size) {
+        byte[] data = new byte[size];
+        for (int i = 0; i < size; i++) {
+            data[i] = (byte) i;
+        }
+        return data;
+    }
+
+    private void testDelete(StorageProvider provider) throws IOException {
+        Storage storage = provider.store(new ByteArrayInputStream(
+                createData(512)));
+
+        storage.delete();
+
+        // getInputStream has to throw an IllegalStateException
+        try {
+            storage.getInputStream();
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+
+        // invoking delete a second time should not have any effect
+        storage.delete();
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/CharsetUtilTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/CharsetUtilTest.java
new file mode 100644
index 0000000..8f3e7ba
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/CharsetUtilTest.java
@@ -0,0 +1,39 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+import junit.framework.TestCase;
+
+public class CharsetUtilTest extends TestCase {
+
+    private static final String SWISS_GERMAN_HELLO = "Gr\374ezi_z\344m\344";
+    private static final String RUSSIAN_HELLO = "\u0412\u0441\u0435\u043C_\u043F\u0440\u0438\u0432\u0435\u0442";
+
+    public void testAllASCII() {
+        String s = "Like hello and stuff";
+        assertTrue(CharsetUtil.isASCII(s));
+    }
+
+    public void testNonASCII() {
+        assertFalse(CharsetUtil.isASCII(SWISS_GERMAN_HELLO));
+        assertFalse(CharsetUtil.isASCII(RUSSIAN_HELLO));
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/MimeUtilTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/MimeUtilTest.java
new file mode 100644
index 0000000..41563a6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/MimeUtilTest.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+import junit.framework.TestCase;
+
+public class MimeUtilTest extends TestCase {
+
+    public void testFold() throws Exception {
+        assertEquals("this is\r\n a test", MimeUtil.fold("this is a test", 68));
+        assertEquals("this is\r\n a test", MimeUtil.fold("this is a test", 69));
+        assertEquals("this\r\n is a test", MimeUtil.fold("this is a test", 70));
+        assertEquals("this  \r\n   is a test", MimeUtil.fold(
+                "this     is a test", 70));
+    }
+
+    public void testFoldOverlyLongNonWhitespace() throws Exception {
+        String ninety = "1234567890123456789012345678901234567890"
+                + "12345678901234567890123456789012345678901234567890";
+        String input = String.format("testing 1 2 %s testing %s", ninety,
+                ninety);
+
+        String expected = String.format(
+                "testing 1 2\r\n %s\r\n testing\r\n %s", ninety, ninety);
+
+        assertEquals(expected, MimeUtil.fold(input, 0));
+    }
+
+    public void testUnfold() throws Exception {
+        assertEquals("", MimeUtil.unfold(""));
+        assertEquals("x", MimeUtil.unfold("x"));
+        assertEquals(" x ", MimeUtil.unfold(" x "));
+
+        assertEquals("", MimeUtil.unfold("\r"));
+        assertEquals("", MimeUtil.unfold("\n"));
+        assertEquals("", MimeUtil.unfold("\r\n"));
+
+        assertEquals(" ", MimeUtil.unfold(" \n"));
+        assertEquals(" ", MimeUtil.unfold("\n "));
+        assertEquals(" ", MimeUtil.unfold(" \r\n"));
+        assertEquals(" ", MimeUtil.unfold("\r\n "));
+
+        assertEquals("this is a test", MimeUtil.unfold("this is\r\n a test"));
+        assertEquals("this is a test", MimeUtil.unfold("this is\r\n a test"));
+        assertEquals("this is a test", MimeUtil.unfold("this\r\n is a test"));
+        assertEquals("this     is a test", MimeUtil
+                .unfold("this  \r\n   is a test"));
+
+        assertEquals("this is a test", MimeUtil
+                .unfold("this\r\n is\r\n a\r\n test"));
+    }
+
+}
diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/StringArrayMapTest.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/StringArrayMapTest.java
new file mode 100644
index 0000000..d8c3039
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/StringArrayMapTest.java
@@ -0,0 +1,138 @@
+/****************************************************************

+ * Licensed to the Apache Software Foundation (ASF) under one   *

+ * or more contributor license agreements.  See the NOTICE file *

+ * distributed with this work for additional information        *

+ * regarding copyright ownership.  The ASF licenses this file   *

+ * to you under the Apache License, Version 2.0 (the            *

+ * "License"); you may not use this file except in compliance   *

+ * with the License.  You may obtain a copy of the License at   *

+ *                                                              *

+ *   http://www.apache.org/licenses/LICENSE-2.0                 *

+ *                                                              *

+ * Unless required by applicable law or agreed to in writing,   *

+ * software distributed under the License is distributed on an  *

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *

+ * KIND, either express or implied.  See the License for the    *

+ * specific language governing permissions and limitations      *

+ * under the License.                                           *

+ ****************************************************************/

+

+package org.apache.james.mime4j.util;

+

+import java.text.Collator;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Collections;

+import java.util.Enumeration;

+import java.util.List;

+import java.util.Locale;

+import java.util.Map;

+

+import junit.framework.TestCase;

+

+public class StringArrayMapTest extends TestCase {

+    private StringArrayMap getSampleMap() {

+        final StringArrayMap map = new StringArrayMap();

+        map.addValue("xYz", "a");

+        map.addValue("Xyz", "B");

+        map.addValue("xyz", "c");

+        map.addValue("xs", "1");

+        map.addValue("XS", "2");

+        map.addValue("foo", "bAr");

+        return map;

+    }

+

+    public void testGetMap() {

+        final Map<String, String[]> map = getSampleMap().getMap();

+        final List<String> keys = new ArrayList<String>(map.keySet());

+        assertEquals(keys.size(), 3);

+        Collections.sort(keys);

+        assertEquals("foo", keys.get(0));

+        assertEquals("xs", keys.get(1));

+        assertEquals("xyz", keys.get(2));

+        final String[] foo = map.get("foo");

+        assertEquals("bAr", foo[0]);

+        final String[] xs = map.get("xs");

+        assertEquals("1", xs[0]);

+        assertEquals("2", xs[1]);

+        final String[] xyz = map.get("xyz");

+        assertEquals(3, xyz.length);

+        assertEquals("a", xyz[0]);

+        assertEquals("B", xyz[1]);

+        assertEquals("c", xyz[2]);

+    }

+

+    public void testGetNameArray() {

+        final String[] names = getSampleMap().getNameArray();

+        assertEquals(3, names.length);

+        Arrays.sort(names);

+        assertEquals("foo", names[0]);

+        assertEquals("xs", names[1]);

+        assertEquals("xyz", names[2]);

+    }

+

+    public void testGetNames() {

+        final Enumeration<String> names = getSampleMap().getNames();

+        assertEquals(new String[]{"foo", "xs", "xyz"}, names);

+    }

+

+    public void testGetValue() {

+        final StringArrayMap map = getSampleMap();

+        assertEquals("bAr", map.getValue("foo"));

+        assertEquals("bAr", map.getValue("FOO"));

+        assertEquals("1", map.getValue("xs"));

+        assertEquals("a", map.getValue("xyz"));

+        assertEquals("a", map.getValue("xyZ"));

+        assertNull(map.getValue("xz"));

+    }

+

+    public void testGetValues() {

+        final StringArrayMap map = getSampleMap();

+        final String[] foo = map.getValues("foo");

+        assertEquals(1, foo.length);

+        assertEquals("bAr", foo[0]);

+        final String[] FOO = map.getValues("FOO");

+        assertEquals(1, FOO.length);

+        assertEquals("bAr", FOO[0]);

+        final String[] xs = map.getValues("xs");

+        assertEquals(2, xs.length);

+        assertEquals("1", xs[0]);

+        assertEquals("2", xs[1]);

+        final String[] XS = map.getValues("XS");

+        assertEquals(2, XS.length);

+        assertEquals("1", XS[0]);

+        assertEquals("2", XS[1]);

+        final String[] xyz = map.getValues("xyz");

+        assertEquals("a", xyz[0]);

+        assertEquals("B", xyz[1]);

+        assertEquals("c", xyz[2]);

+        final String[] XYZ = map.getValues("XYZ");

+        assertEquals("a", XYZ[0]);

+        assertEquals("B", XYZ[1]);

+        assertEquals("c", XYZ[2]);

+        assertNull(map.getValues("xz"));

+    }

+

+    private void assertEquals(String[] pArray, Enumeration<String> pEnum) {

+        final List<String> list = new ArrayList<String>();

+        while (pEnum.hasMoreElements()) {

+            list.add(pEnum.nextElement());

+        }

+        Collections.sort(list, Collator.getInstance(Locale.US));

+        assertEquals(pArray.length, list.size());

+        for (int i = 0;  i < pArray.length;  i++) {

+            assertEquals(pArray[i], list.get(i));

+        }

+    }

+

+    public void testGetValueEnum() {

+        final StringArrayMap map = getSampleMap();

+        assertEquals(new String[]{"bAr"}, map.getValueEnum("foo"));

+        assertEquals(new String[]{"bAr"}, map.getValueEnum("FOO"));

+        assertEquals(new String[]{"1", "2"}, map.getValueEnum("xs"));

+        assertEquals(new String[]{"1", "2"}, map.getValueEnum("Xs"));

+        assertEquals(new String[]{"a", "B", "c"}, map.getValueEnum("xyz"));

+        assertEquals(new String[]{"a", "B", "c"}, map.getValueEnum("XYZ"));

+        assertNull(map.getValues("xz"));

+    }

+}

diff --git a/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/TestByteArrayBuffer.java b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/TestByteArrayBuffer.java
new file mode 100644
index 0000000..97579bb
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/java/org/apache/james/mime4j/util/TestByteArrayBuffer.java
@@ -0,0 +1,169 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.util;
+
+import org.apache.james.mime4j.util.ByteArrayBuffer;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link ByteArrayBuffer}.
+ */
+public class TestByteArrayBuffer extends TestCase {
+
+    public void testConstructor() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(16);
+        assertEquals(16, buffer.capacity()); 
+        assertEquals(0, buffer.length());
+        assertNotNull(buffer.buffer());
+        assertEquals(16, buffer.buffer().length);
+        try {
+            new ByteArrayBuffer(-1);
+            fail("IllegalArgumentException should have been thrown");
+        } catch (IllegalArgumentException ex) {
+            // expected
+        }
+    }
+    
+    public void testSimpleAppend() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(16);
+        assertEquals(16, buffer.capacity()); 
+        assertEquals(0, buffer.length());
+        byte[] b1 = buffer.toByteArray();
+        assertNotNull(b1);
+        assertEquals(0, b1.length);
+        assertTrue(buffer.isEmpty());
+        assertFalse(buffer.isFull());
+        
+        byte[] tmp = new byte[] { 1, 2, 3, 4};
+        buffer.append(tmp, 0, tmp.length);
+        assertEquals(16, buffer.capacity()); 
+        assertEquals(4, buffer.length());
+        assertFalse(buffer.isEmpty());
+        assertFalse(buffer.isFull());
+        
+        byte[] b2 = buffer.toByteArray();
+        assertNotNull(b2);
+        assertEquals(4, b2.length);
+        for (int i = 0; i < tmp.length; i++) {
+            assertEquals(tmp[i], b2[i]);
+            assertEquals(tmp[i], buffer.byteAt(i));
+        }
+        buffer.clear();
+        assertEquals(16, buffer.capacity()); 
+        assertEquals(0, buffer.length());
+        assertTrue(buffer.isEmpty());
+        assertFalse(buffer.isFull());
+    }
+    
+    public void testExpandAppend() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(4);
+        assertEquals(4, buffer.capacity()); 
+        
+        byte[] tmp = new byte[] { 1, 2, 3, 4};
+        buffer.append(tmp, 0, 2);
+        buffer.append(tmp, 0, 4);
+        buffer.append(tmp, 0, 0);
+
+        assertEquals(8, buffer.capacity()); 
+        assertEquals(6, buffer.length());
+        
+        buffer.append(tmp, 0, 4);
+        
+        assertEquals(16, buffer.capacity()); 
+        assertEquals(10, buffer.length());
+    }
+    
+    public void testInvalidAppend() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(4);
+        buffer.append((byte[])null, 0, 0);
+
+        byte[] tmp = new byte[] { 1, 2, 3, 4};
+        try {
+            buffer.append(tmp, -1, 0);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 0, -1);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 0, 8);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 10, Integer.MAX_VALUE);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 2, 4);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+    }
+
+    public void testAppendOneByte() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(4);
+        assertEquals(4, buffer.capacity()); 
+        
+        byte[] tmp = new byte[] { 1, 127, -1, -128, 1, -2};
+        for (byte b : tmp) {
+            buffer.append(b);
+        }
+        assertEquals(8, buffer.capacity()); 
+        assertEquals(6, buffer.length());
+        
+        for (int i = 0; i < tmp.length; i++) {
+            assertEquals(tmp[i], buffer.byteAt(i));
+        }
+    }
+    
+    public void testSetLength() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(4);
+        buffer.setLength(2);
+        assertEquals(2, buffer.length());
+    }
+    
+    public void testSetInvalidLength() throws Exception {
+        ByteArrayBuffer buffer = new ByteArrayBuffer(4);
+        try {
+            buffer.setLength(-2);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.setLength(200);
+            fail("IndexOutOfBoundsException should have been thrown");
+        } catch (IndexOutOfBoundsException ex) {
+            // expected
+        }
+    }
+    
+}
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.msg
new file mode 100644
index 0000000..3b4f0b5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.msg
@@ -0,0 +1,11 @@
+Content-type: message/rfc822

+Content-transfer-encoding: base64

+Subject: a multipart message/rfc822 which has been base64-encoded

+

+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSItLS0tLS0tLS0tLS0yOTlB

+NzBCMzM5QjY1QTkzNTQyRDJBRSIKClRoaXMgaXMgYSBtdWx0aS1wYXJ0IG1lc3NhZ2UgaW4gTUlN

+RSBmb3JtYXQuCgotLS0tLS0tLS0tLS0tLTI5OUE3MEIzMzlCNjVBOTM1NDJEMkFFCkNvbnRlbnQt

+VHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11cy1hc2NpaQpDb250ZW50LVRyYW5zZmVyLUVuY29k

+aW5nOiA3Yml0CgpUZXh0IGJvZHkKCi0tLS0tLS0tLS0tLS0tMjk5QTcwQjMzOUI2NUE5MzU0MkQy

+QUUtLQpUaGF0IHdhcyBhIG11bHRpLXBhcnQgbWVzc2FnZSBpbiBNSU1FIGZvcm1hdC4K

+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.out b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.out
new file mode 100644
index 0000000..daad166
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.out
@@ -0,0 +1,11 @@
+Content-type: message/rfc822

+Content-transfer-encoding: base64

+Subject: a multipart message/rfc822 which has been base64-encoded

+

+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSItLS0tLS0tLS0tLS0yOTlB

+NzBCMzM5QjY1QTkzNTQyRDJBRSINCg0KVGhpcyBpcyBhIG11bHRpLXBhcnQgbWVzc2FnZSBpbiBN

+SU1FIGZvcm1hdC4KDQotLS0tLS0tLS0tLS0tLTI5OUE3MEIzMzlCNjVBOTM1NDJEMkFFDQpDb250

+ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXMtYXNjaWkNCkNvbnRlbnQtVHJhbnNmZXIt

+RW5jb2Rpbmc6IDdiaXQNCg0KVGV4dCBib2R5Cg0KLS0tLS0tLS0tLS0tLS0yOTlBNzBCMzM5QjY1

+QTkzNTQyRDJBRS0tDQpUaGF0IHdhcyBhIG11bHRpLXBhcnQgbWVzc2FnZSBpbiBNSU1FIGZvcm1h

+dC4K

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.xml
new file mode 100644
index 0000000..8fd0306
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64.xml
@@ -0,0 +1,35 @@
+<message>

+<header>

+<field>

+Content-type: message/rfc822</field>

+<field>

+Content-transfer-encoding: base64</field>

+<field>

+Subject: a multipart message/rfc822 which has been base64-encoded</field>

+</header>

+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"</field>

+</header>

+<multipart>

+<preamble>

+This is a multi-part message in MIME format.
+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body
+</body>

+</body-part>

+<epilogue>

+That was a multi-part message in MIME format.
+</epilogue>

+</multipart>

+</message>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64_decoded.xml
new file mode 100644
index 0000000..7f19d37
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64_decoded.xml
@@ -0,0 +1,33 @@
+<message>

+<header>

+<field>

+Content-type: message/rfc822</field>

+<field>

+Content-transfer-encoding: base64</field>

+<field>

+Subject: a multipart message/rfc822 which has been base64-encoded</field>

+</header>

+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"</field>

+</header>

+<multipart>

+<preamble>

+This is a multi-part message in MIME format.
+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="bad-newlines-multiple-parts-base64_decoded_1_1_1.txt"/>

+</body-part>

+<epilogue>

+That was a multi-part message in MIME format.
+</epilogue>

+</multipart>

+</message>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64_decoded_1_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64_decoded_1_1_1.txt
new file mode 100644
index 0000000..7f628f3
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts-base64_decoded_1_1_1.txt
@@ -0,0 +1 @@
+Text body
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.msg
new file mode 100644
index 0000000..e485490
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.msg
@@ -0,0 +1,12 @@
+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"
+
+This is a multi-part message in MIME format.
+
+--------------299A70B339B65A93542D2AE
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+
+Text body
+
+--------------299A70B339B65A93542D2AE--
+That was a multi-part message in MIME format.
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.out b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.out
new file mode 100644
index 0000000..1384916
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.out
@@ -0,0 +1,12 @@
+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"

+

+This is a multi-part message in MIME format.
+

+--------------299A70B339B65A93542D2AE

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body
+

+--------------299A70B339B65A93542D2AE--

+That was a multi-part message in MIME format.
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.xml
new file mode 100644
index 0000000..a4f8f12
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts.xml
@@ -0,0 +1,25 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"</field>

+</header>

+<multipart>

+<preamble>

+This is a multi-part message in MIME format.
+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body
+</body>

+</body-part>

+<epilogue>

+That was a multi-part message in MIME format.
+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts_decoded.xml
new file mode 100644
index 0000000..a64a007
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts_decoded.xml
@@ -0,0 +1,23 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"</field>

+</header>

+<multipart>

+<preamble>

+This is a multi-part message in MIME format.
+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="bad-newlines-multiple-parts_decoded_1_1.txt"/>

+</body-part>

+<epilogue>

+That was a multi-part message in MIME format.
+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts_decoded_1_1.txt
new file mode 100644
index 0000000..7f628f3
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/bad-newlines-multiple-parts_decoded_1_1.txt
@@ -0,0 +1 @@
+Text body
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.msg
new file mode 100644
index 0000000..e86ba45
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.msg
@@ -0,0 +1,11 @@
+Content-type: text/plain

+Content-transfer-encoding: base64

+Subject: a multipart message/rfc822 which has been base64-encoded as plain text

+

+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSItLS0tLS0tLS0tLS0yOTlB

+NzBCMzM5QjY1QTkzNTQyRDJBRSIKClRoaXMgaXMgYSBtdWx0aS1wYXJ0IG1lc3NhZ2UgaW4gTUlN

+RSBmb3JtYXQuCgotLS0tLS0tLS0tLS0tLTI5OUE3MEIzMzlCNjVBOTM1NDJEMkFFCkNvbnRlbnQt

+VHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11cy1hc2NpaQpDb250ZW50LVRyYW5zZmVyLUVuY29k

+aW5nOiA3Yml0CgpUZXh0IGJvZHkKCi0tLS0tLS0tLS0tLS0tMjk5QTcwQjMzOUI2NUE5MzU0MkQy

+QUUtLQpUaGF0IHdhcyBhIG11bHRpLXBhcnQgbWVzc2FnZSBpbiBNSU1FIGZvcm1hdC4K

+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.out b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.out
new file mode 100644
index 0000000..343f4dd
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.out
@@ -0,0 +1,10 @@
+Content-type: text/plain

+Content-transfer-encoding: base64

+Subject: a multipart message/rfc822 which has been base64-encoded as plain text

+

+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSItLS0tLS0tLS0tLS0yOTlB

+NzBCMzM5QjY1QTkzNTQyRDJBRSIKClRoaXMgaXMgYSBtdWx0aS1wYXJ0IG1lc3NhZ2UgaW4gTUlN

+RSBmb3JtYXQuCgotLS0tLS0tLS0tLS0tLTI5OUE3MEIzMzlCNjVBOTM1NDJEMkFFCkNvbnRlbnQt

+VHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11cy1hc2NpaQpDb250ZW50LVRyYW5zZmVyLUVuY29k

+aW5nOiA3Yml0CgpUZXh0IGJvZHkKCi0tLS0tLS0tLS0tLS0tMjk5QTcwQjMzOUI2NUE5MzU0MkQy

+QUUtLQpUaGF0IHdhcyBhIG11bHRpLXBhcnQgbWVzc2FnZSBpbiBNSU1FIGZvcm1hdC4K

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.xml
new file mode 100644
index 0000000..eb87e0a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text.xml
@@ -0,0 +1,19 @@
+<message>

+<header>

+<field>

+Content-type: text/plain</field>

+<field>

+Content-transfer-encoding: base64</field>

+<field>

+Subject: a multipart message/rfc822 which has been base64-encoded as plain text</field>

+</header>

+<body>

+Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PSItLS0tLS0tLS0tLS0yOTlB

+NzBCMzM5QjY1QTkzNTQyRDJBRSIKClRoaXMgaXMgYSBtdWx0aS1wYXJ0IG1lc3NhZ2UgaW4gTUlN

+RSBmb3JtYXQuCgotLS0tLS0tLS0tLS0tLTI5OUE3MEIzMzlCNjVBOTM1NDJEMkFFCkNvbnRlbnQt

+VHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11cy1hc2NpaQpDb250ZW50LVRyYW5zZmVyLUVuY29k

+aW5nOiA3Yml0CgpUZXh0IGJvZHkKCi0tLS0tLS0tLS0tLS0tMjk5QTcwQjMzOUI2NUE5MzU0MkQy

+QUUtLQpUaGF0IHdhcyBhIG11bHRpLXBhcnQgbWVzc2FnZSBpbiBNSU1FIGZvcm1hdC4K

+

+</body>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text_decoded.xml
new file mode 100644
index 0000000..5fa6d89
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text_decoded.xml
@@ -0,0 +1,11 @@
+<message>

+<header>

+<field>

+Content-type: text/plain</field>

+<field>

+Content-transfer-encoding: base64</field>

+<field>

+Subject: a multipart message/rfc822 which has been base64-encoded as plain text</field>

+</header>

+<text-body name="base64-encoded-text_decoded_1.txt"/>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text_decoded_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text_decoded_1.txt
new file mode 100644
index 0000000..e485490
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64-encoded-text_decoded_1.txt
@@ -0,0 +1,12 @@
+Content-Type: multipart/mixed; boundary="------------299A70B339B65A93542D2AE"
+
+This is a multi-part message in MIME format.
+
+--------------299A70B339B65A93542D2AE
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+
+Text body
+
+--------------299A70B339B65A93542D2AE--
+That was a multi-part message in MIME format.
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.msg
new file mode 100644
index 0000000..d974d3b
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.msg
@@ -0,0 +1,11 @@
+MIME-Version: 1.0

+Content-Type: message/rfc822

+Subject: the body is a base64 encode rfc822 message including another base64 encoded rfc822 message

+Content-Transfer-Encoding: base64

+

+TUlNRS1WZXJzaW9uOiAxLjANClN1YmplY3Q6IGEgc2ltcGxlIHJmYzgyMiBtZXNzYWdlIGVuY29k

+ZWQgaW4gYSBiYXNlNjQgYm9keS4NCkNvbnRlbnQtVHlwZTogbWVzc2FnZS9yZmM4MjINCkNvbnRl

+bnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NA0KDQpRMjl1ZEdWdWRDMVVlWEJsT2lCMFpYaDBM

+M0JzWVdsdU95QmphR0Z5YzJWMFBYVnpMV0Z6WTJscERRcERiMjUwWlc1MExWUnlZVzV6DQpabVZ5

+TFVWdVkyOWthVzVuT2lBM1ltbDBEUW9OQ2xSbGVIUWdZbTlrZVFvTkNnPT0NCg0K

+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.out b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.out
new file mode 100644
index 0000000..4d87a04
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.out
@@ -0,0 +1,10 @@
+MIME-Version: 1.0

+Content-Type: message/rfc822

+Subject: the body is a base64 encode rfc822 message including another base64 encoded rfc822 message

+Content-Transfer-Encoding: base64

+

+TUlNRS1WZXJzaW9uOiAxLjANClN1YmplY3Q6IGEgc2ltcGxlIHJmYzgyMiBtZXNzYWdlIGVuY29k

+ZWQgaW4gYSBiYXNlNjQgYm9keS4NCkNvbnRlbnQtVHlwZTogbWVzc2FnZS9yZmM4MjINCkNvbnRl

+bnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NA0KDQpRMjl1ZEdWdWRDMVVlWEJsT2lCMFpYaDBM

+M0JzWVdsdU95QmphR0Z5YzJWMFBYVnpMV0Z6WTJscERRcERiMjUwWlc1MExWUnlZVzV6DQpabVZ5

+TFVWdVkyOWthVzVuT2lBM1ltbDBEUW9OQ2xSbGVIUWdZbTlrZVFvTkNnPT0NCg==

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.xml
new file mode 100644
index 0000000..f2d8c69
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested.xml
@@ -0,0 +1,36 @@
+<message>

+<header>

+<field>

+MIME-Version: 1.0</field>

+<field>

+Content-Type: message/rfc822</field>

+<field>

+Subject: the body is a base64 encode rfc822 message including another base64 encoded rfc822 message</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<message>

+<header>

+<field>

+MIME-Version: 1.0</field>

+<field>

+Subject: a simple rfc822 message encoded in a base64 body.</field>

+<field>

+Content-Type: message/rfc822</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<message>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body
+

+</body>

+</message>

+</message>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested_decoded.xml
new file mode 100644
index 0000000..73ba4ff
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested_decoded.xml
@@ -0,0 +1,33 @@
+<message>

+<header>

+<field>

+MIME-Version: 1.0</field>

+<field>

+Content-Type: message/rfc822</field>

+<field>

+Subject: the body is a base64 encode rfc822 message including another base64 encoded rfc822 message</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<message>

+<header>

+<field>

+MIME-Version: 1.0</field>

+<field>

+Subject: a simple rfc822 message encoded in a base64 body.</field>

+<field>

+Content-Type: message/rfc822</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<message>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="base64encoded-rfc822message-nested_decoded_1_1_1.txt"/>

+</message>

+</message>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested_decoded_1_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested_decoded_1_1_1.txt
new file mode 100644
index 0000000..3d76cf4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message-nested_decoded_1_1_1.txt
@@ -0,0 +1,2 @@
+Text body
+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.msg
new file mode 100644
index 0000000..7f4ce63
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.msg
@@ -0,0 +1,8 @@
+MIME-Version: 1.0

+Subject: a simple rfc822 message encoded in a base64 body.

+Content-Type: message/rfc822

+Content-Transfer-Encoding: base64

+

+Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXVzLWFzY2lpDQpDb250ZW50LVRyYW5z

+ZmVyLUVuY29kaW5nOiA3Yml0DQoNClRleHQgYm9keQoNCg==

+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.out b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.out
new file mode 100644
index 0000000..3de34d6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.out
@@ -0,0 +1,7 @@
+MIME-Version: 1.0

+Subject: a simple rfc822 message encoded in a base64 body.

+Content-Type: message/rfc822

+Content-Transfer-Encoding: base64

+

+Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXVzLWFzY2lpDQpDb250ZW50LVRyYW5z

+ZmVyLUVuY29kaW5nOiA3Yml0DQoNClRleHQgYm9keQoNCg==

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.xml
new file mode 100644
index 0000000..d9e5e0f
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message.xml
@@ -0,0 +1,24 @@
+<message>

+<header>

+<field>

+MIME-Version: 1.0</field>

+<field>

+Subject: a simple rfc822 message encoded in a base64 body.</field>

+<field>

+Content-Type: message/rfc822</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<message>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body
+

+</body>

+</message>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message_decoded.xml
new file mode 100644
index 0000000..6d75164
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message_decoded.xml
@@ -0,0 +1,21 @@
+<message>

+<header>

+<field>

+MIME-Version: 1.0</field>

+<field>

+Subject: a simple rfc822 message encoded in a base64 body.</field>

+<field>

+Content-Type: message/rfc822</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<message>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="base64encoded-rfc822message_decoded_1_1.txt"/>

+</message>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message_decoded_1_1.txt
new file mode 100644
index 0000000..3d76cf4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/base64encoded-rfc822message_decoded_1_1.txt
@@ -0,0 +1,2 @@
+Text body
+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.msg
new file mode 100644
index 0000000..3cde6c1
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.msg
@@ -0,0 +1,13 @@
+Return-Path: foo@example.com

+Subject: Simple Subject

+From: foo@example.com

+To: bar@example.com

+Cc: recipient1@example.com,recipient2@example.com, localrecipient

+Date: Wed, 11 Feb 98 11:51 CST

+

+This is a very simple message with a simple body and no weird things at 

+all.

+

+this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line 

+

+Done.
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.out b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.out
new file mode 100644
index 0000000..3cde6c1
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.out
@@ -0,0 +1,13 @@
+Return-Path: foo@example.com

+Subject: Simple Subject

+From: foo@example.com

+To: bar@example.com

+Cc: recipient1@example.com,recipient2@example.com, localrecipient

+Date: Wed, 11 Feb 98 11:51 CST

+

+This is a very simple message with a simple body and no weird things at 

+all.

+

+this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line 

+

+Done.
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.xml
new file mode 100644
index 0000000..283bc3a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines.xml
@@ -0,0 +1,23 @@
+<message>

+<header>

+<field>

+Return-Path: foo@example.com</field>

+<field>

+Subject: Simple Subject</field>

+<field>

+From: foo@example.com</field>

+<field>

+To: bar@example.com</field>

+<field>

+Cc: recipient1@example.com,recipient2@example.com, localrecipient</field>

+<field>

+Date: Wed, 11 Feb 98 11:51 CST</field>

+</header>

+<body>

+This is a very simple message with a simple body and no weird things at 

+all.

+

+this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line 

+

+Done.</body>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines_decoded.xml
new file mode 100644
index 0000000..ba7eada
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines_decoded.xml
@@ -0,0 +1,17 @@
+<message>

+<header>

+<field>

+Return-Path: foo@example.com</field>

+<field>

+Subject: Simple Subject</field>

+<field>

+From: foo@example.com</field>

+<field>

+To: bar@example.com</field>

+<field>

+Cc: recipient1@example.com,recipient2@example.com, localrecipient</field>

+<field>

+Date: Wed, 11 Feb 98 11:51 CST</field>

+</header>

+<text-body name="basic-plain-very-long-lines_decoded_1.txt"/>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines_decoded_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines_decoded_1.txt
new file mode 100644
index 0000000..0799fa4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-very-long-lines_decoded_1.txt
@@ -0,0 +1,6 @@
+This is a very simple message with a simple body and no weird things at 

+all.

+

+this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line this is a very very long line 

+

+Done.
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.msg
new file mode 100644
index 0000000..b63d584
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.msg
@@ -0,0 +1,12 @@
+Return-Path: foo@example.com

+Subject: Simple Subject

+From: foo@example.com

+To: bar@example.com

+Cc: recipient1@example.com,recipient2@example.com, localrecipient

+Date: Wed, 11 Feb 98 11:51 CST

+ 

+This is a very simple message with a simple body but the separator

+between header and body contains an additional space: 

+CRLF<space>CRLF.

+

+This results in a bogus header.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.out b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.out
new file mode 100644
index 0000000..6153a12
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.out
@@ -0,0 +1,9 @@
+Return-Path: foo@example.com

+Subject: Simple Subject

+From: foo@example.com

+To: bar@example.com

+Cc: recipient1@example.com,recipient2@example.com, localrecipient

+Date: Wed, 11 Feb 98 11:51 CST

+ 

+

+This results in a bogus header.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.xml
new file mode 100644
index 0000000..eaa98b6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator.xml
@@ -0,0 +1,20 @@
+<message>

+<header>

+<field>

+Return-Path: foo@example.com</field>

+<field>

+Subject: Simple Subject</field>

+<field>

+From: foo@example.com</field>

+<field>

+To: bar@example.com</field>

+<field>

+Cc: recipient1@example.com,recipient2@example.com, localrecipient</field>

+<field>

+Date: Wed, 11 Feb 98 11:51 CST

+ </field>

+</header>

+<body>

+This results in a bogus header.

+</body>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator_decoded.xml
new file mode 100644
index 0000000..c8018f6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator_decoded.xml
@@ -0,0 +1,18 @@
+<message>

+<header>

+<field>

+Return-Path: foo@example.com</field>

+<field>

+Subject: Simple Subject</field>

+<field>

+From: foo@example.com</field>

+<field>

+To: bar@example.com</field>

+<field>

+Cc: recipient1@example.com,recipient2@example.com, localrecipient</field>

+<field>

+Date: Wed, 11 Feb 98 11:51 CST

+ </field>

+</header>

+<text-body name="basic-plain-with-bad-header-separator_decoded_1.txt"/>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator_decoded_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator_decoded_1.txt
new file mode 100644
index 0000000..27668a1
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain-with-bad-header-separator_decoded_1.txt
@@ -0,0 +1 @@
+This results in a bogus header.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.msg
new file mode 100644
index 0000000..1d469d7
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.msg
@@ -0,0 +1,9 @@
+Return-Path: foo@example.com

+Subject: Simple Subject

+From: foo@example.com

+To: bar@example.com

+Cc: recipient1@example.com,recipient2@example.com, localrecipient

+Date: Wed, 11 Feb 98 11:51 CST

+

+This is a very simple message with a simple body and no weird things at 

+all.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.out b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.out
new file mode 100644
index 0000000..1d469d7
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.out
@@ -0,0 +1,9 @@
+Return-Path: foo@example.com

+Subject: Simple Subject

+From: foo@example.com

+To: bar@example.com

+Cc: recipient1@example.com,recipient2@example.com, localrecipient

+Date: Wed, 11 Feb 98 11:51 CST

+

+This is a very simple message with a simple body and no weird things at 

+all.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.xml
new file mode 100644
index 0000000..80c6c02
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain.xml
@@ -0,0 +1,20 @@
+<message>

+<header>

+<field>

+Return-Path: foo@example.com</field>

+<field>

+Subject: Simple Subject</field>

+<field>

+From: foo@example.com</field>

+<field>

+To: bar@example.com</field>

+<field>

+Cc: recipient1@example.com,recipient2@example.com, localrecipient</field>

+<field>

+Date: Wed, 11 Feb 98 11:51 CST</field>

+</header>

+<body>

+This is a very simple message with a simple body and no weird things at 

+all.

+</body>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain_decoded.xml
new file mode 100644
index 0000000..7b8e2e5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain_decoded.xml
@@ -0,0 +1,17 @@
+<message>

+<header>

+<field>

+Return-Path: foo@example.com</field>

+<field>

+Subject: Simple Subject</field>

+<field>

+From: foo@example.com</field>

+<field>

+To: bar@example.com</field>

+<field>

+Cc: recipient1@example.com,recipient2@example.com, localrecipient</field>

+<field>

+Date: Wed, 11 Feb 98 11:51 CST</field>

+</header>

+<text-body name="basic-plain_decoded_1.txt"/>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain_decoded_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain_decoded_1.txt
new file mode 100644
index 0000000..2ff6c3d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/basic-plain_decoded_1.txt
@@ -0,0 +1,2 @@
+This is a very simple message with a simple body and no weird things at 

+all.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.msg
new file mode 100644
index 0000000..1a2444b
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.msg
@@ -0,0 +1,21 @@
+Content-Type: multipart/mixed; boundary="boundary"

+

+--boundary This should be ignored Content-Type: message/rfc822

+Content-Type: text/plain

+

+first part

+

+--boundary-- This should be ignored at all and not part of the epilogue.

+

+From the RFC about ending boundary:

+

+===================================================================

+NOTE TO IMPLEMENTORS:  Boundary string comparisons must compare the

+boundary value with the beginning of each candidate line.  An exact

+match of the entire candidate line is not required; it is sufficient

+that the boundary appear in its entirety following the CRLF.

+===================================================================

+

+--boundary--

+

+The above boundary should be part of the epilogue, too.
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.out b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.out
new file mode 100644
index 0000000..be60d5a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.out
@@ -0,0 +1,22 @@
+Content-Type: multipart/mixed; boundary="boundary"

+

+

+--boundary

+Content-Type: text/plain

+

+first part

+

+--boundary--

+

+From the RFC about ending boundary:

+

+===================================================================

+NOTE TO IMPLEMENTORS:  Boundary string comparisons must compare the

+boundary value with the beginning of each candidate line.  An exact

+match of the entire candidate line is not required; it is sufficient

+that the boundary appear in its entirety following the CRLF.

+===================================================================

+

+--boundary--

+

+The above boundary should be part of the epilogue, too.
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.xml
new file mode 100644
index 0000000..df8a92b
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries.xml
@@ -0,0 +1,33 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="boundary"</field>

+</header>

+<multipart>

+<preamble>

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<body>

+first part

+</body>

+</body-part>

+<epilogue>

+

+From the RFC about ending boundary:

+

+===================================================================

+NOTE TO IMPLEMENTORS:  Boundary string comparisons must compare the

+boundary value with the beginning of each candidate line.  An exact

+match of the entire candidate line is not required; it is sufficient

+that the boundary appear in its entirety following the CRLF.

+===================================================================

+

+--boundary--

+

+The above boundary should be part of the epilogue, too.</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries_decoded.xml
new file mode 100644
index 0000000..fdeb7c2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries_decoded.xml
@@ -0,0 +1,31 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="boundary"</field>

+</header>

+<multipart>

+<preamble>

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<text-body name="ending-boundaries_decoded_1_1.txt"/>

+</body-part>

+<epilogue>

+

+From the RFC about ending boundary:

+

+===================================================================

+NOTE TO IMPLEMENTORS:  Boundary string comparisons must compare the

+boundary value with the beginning of each candidate line.  An exact

+match of the entire candidate line is not required; it is sufficient

+that the boundary appear in its entirety following the CRLF.

+===================================================================

+

+--boundary--

+

+The above boundary should be part of the epilogue, too.</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries_decoded_1_1.txt
new file mode 100644
index 0000000..64d7434
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/ending-boundaries_decoded_1_1.txt
@@ -0,0 +1 @@
+first part

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/example.msg
new file mode 100644
index 0000000..cbab741
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example.msg
@@ -0,0 +1,149 @@
+Return-Path: <robertburrelldonkin@blueyonder.co.uk>

+Received: (qmail 18554 invoked from network); 25 May 2008 14:38:53 -0000

+Received: from unknown (HELO p3presmtp01-16.prod.phx3.secureserver.net)

+        ([208.109.80.165]) (envelope-sender <rdonkin-owner@locus.apache.org>) by

+        smtp20-01.prod.mesa1.secureserver.net (qmail-1.03) with SMTP for

+        <asf@xmlmapt.org>; 25 May 2008 14:38:53 -0000

+Received: (qmail 9751 invoked from network); 25 May 2008 14:38:53 -0000

+Received: from minotaur.apache.org ([140.211.11.9]) (envelope-sender

+        <rdonkin-owner@locus.apache.org>) by

+        p3presmtp01-16.prod.phx3.secureserver.net (qmail-ldap-1.03) with SMTP for

+        <asf@xmlmapt.org>; 25 May 2008 14:38:50 -0000

+Received: (qmail 46768 invoked by uid 1289); 25 May 2008 14:38:46 -0000

+Delivered-To: rdonkin@locus.apache.org

+Received: (qmail 46763 invoked from network); 25 May 2008 14:38:46 -0000

+Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by

+        minotaur.apache.org with SMTP; 25 May 2008 14:38:46 -0000

+Received: (qmail 61275 invoked by uid 500); 25 May 2008 14:38:48 -0000

+Delivered-To: apmail-rdonkin@apache.org

+Delivered-To: rob@localhost

+Delivered-To: rob@localhost

+Received: (qmail 61272 invoked by uid 99); 25 May 2008 14:38:48 -0000

+Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)

+        by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008 07:38:48 -0700

+X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS

+X-Spam-Check-By: apache.org

+Received-SPF: pass (athena.apache.org: domain of

+        robertburrelldonkin@blueyonder.co.uk designates 195.188.213.5 as permitted

+        sender)

+Received: from [195.188.213.5] (HELO smtp-out2.blueyonder.co.uk)

+        (195.188.213.5) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008

+        14:38:00 +0000

+Received: from [172.23.170.140] (helo=anti-virus02-07) by

+        smtp-out2.blueyonder.co.uk with smtp (Exim 4.52) id 1K0HMV-00087e-HY for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:15 +0100

+Received: from [82.38.65.6] (helo=[10.0.0.27]) by

+        asmtp-out5.blueyonder.co.uk with esmtpa (Exim 4.52) id 1K0HMU-0001A2-3q for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:14 +0100

+Subject: This is an example of a multipart mixed email with image content

+From: Robert Burrell Donkin <robertburrelldonkin@blueyonder.co.uk>

+To: Robert Burrell Donkin <rdonkin@apache.org>

+Content-Type: multipart/mixed; boundary="=-tIdGYVstQJghyEDATnJ+"

+Date: Sun, 25 May 2008 15:38:13 +0100

+Message-Id: <1211726293.5772.10.camel@localhost>

+Mime-Version: 1.0

+X-Mailer: Evolution 2.12.3 

+X-Virus-Checked: Checked by ClamAV on apache.org

+X-Nonspam: None

+X-fetched-from: mail.xmlmapt.org

+X-Evolution-Source: imap://rob@thebes/

+

+

+--=-tIdGYVstQJghyEDATnJ+

+Content-Type: text/plain

+Content-Transfer-Encoding: 7bit

+

+Licensed to the Apache Software Foundation (ASF) under one

+or more contributor license agreements.  See the NOTICE file

+distributed with this work for additional information

+regarding copyright ownership.  The ASF licenses this file

+to you under the Apache License, Version 2.0 (the

+"License"); you may not use this file except in compliance

+with the License.  You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+ 

+Unless required by applicable law or agreed to in writing,

+software distributed under the License is distributed on an

+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+KIND, either express or implied.  See the License for the

+specific language governing permissions and limitations

+under the License.

+--=-tIdGYVstQJghyEDATnJ+

+Content-Disposition: attachment; filename=blob.png;

+   modification-date="Sun, 21 Jun 2008 15:32:18 +0000"; creation-date="Sat, 20 Jun 2008 10:15:09 +0000"; read-date="Mon, 22 Jun 2008 12:08:56 +0000";size=10234;

+Content-Type: image/png; name=blob.png

+Content-Transfer-Encoding: base64

+

+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL

+EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo

+IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ

+/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE

+E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF

+iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp

+rQAAAABJRU5ErkJggg==

+

+

+--=-tIdGYVstQJghyEDATnJ+

+Content-Disposition: attachment; filename=blob.png

+Content-Type: image/png; name=blob.png

+Content-Transfer-Encoding: base64

+

+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL

+EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo

+IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ

+/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE

+E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF

+iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp

+rQAAAABJRU5ErkJggg==

+

+

+--=-tIdGYVstQJghyEDATnJ+

+Content-Disposition: attachment; filename=rhubarb.txt

+Content-Type: text/plain; name=rhubarb.txt; charset=us-ascii

+Content-Language: en, en-US, en-CA

+Content-Transfer-Encoding: quoted-printable

+

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb

+

+--=-tIdGYVstQJghyEDATnJ+--

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example.out b/apache-mime4j-0.6/src/test/resources/testmsgs/example.out
new file mode 100644
index 0000000..5dbe309
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example.out
@@ -0,0 +1,147 @@
+Return-Path: <robertburrelldonkin@blueyonder.co.uk>

+Received: (qmail 18554 invoked from network); 25 May 2008 14:38:53 -0000

+Received: from unknown (HELO p3presmtp01-16.prod.phx3.secureserver.net)

+        ([208.109.80.165]) (envelope-sender <rdonkin-owner@locus.apache.org>) by

+        smtp20-01.prod.mesa1.secureserver.net (qmail-1.03) with SMTP for

+        <asf@xmlmapt.org>; 25 May 2008 14:38:53 -0000

+Received: (qmail 9751 invoked from network); 25 May 2008 14:38:53 -0000

+Received: from minotaur.apache.org ([140.211.11.9]) (envelope-sender

+        <rdonkin-owner@locus.apache.org>) by

+        p3presmtp01-16.prod.phx3.secureserver.net (qmail-ldap-1.03) with SMTP for

+        <asf@xmlmapt.org>; 25 May 2008 14:38:50 -0000

+Received: (qmail 46768 invoked by uid 1289); 25 May 2008 14:38:46 -0000

+Delivered-To: rdonkin@locus.apache.org

+Received: (qmail 46763 invoked from network); 25 May 2008 14:38:46 -0000

+Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by

+        minotaur.apache.org with SMTP; 25 May 2008 14:38:46 -0000

+Received: (qmail 61275 invoked by uid 500); 25 May 2008 14:38:48 -0000

+Delivered-To: apmail-rdonkin@apache.org

+Delivered-To: rob@localhost

+Delivered-To: rob@localhost

+Received: (qmail 61272 invoked by uid 99); 25 May 2008 14:38:48 -0000

+Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)

+        by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008 07:38:48 -0700

+X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS

+X-Spam-Check-By: apache.org

+Received-SPF: pass (athena.apache.org: domain of

+        robertburrelldonkin@blueyonder.co.uk designates 195.188.213.5 as permitted

+        sender)

+Received: from [195.188.213.5] (HELO smtp-out2.blueyonder.co.uk)

+        (195.188.213.5) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008

+        14:38:00 +0000

+Received: from [172.23.170.140] (helo=anti-virus02-07) by

+        smtp-out2.blueyonder.co.uk with smtp (Exim 4.52) id 1K0HMV-00087e-HY for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:15 +0100

+Received: from [82.38.65.6] (helo=[10.0.0.27]) by

+        asmtp-out5.blueyonder.co.uk with esmtpa (Exim 4.52) id 1K0HMU-0001A2-3q for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:14 +0100

+Subject: This is an example of a multipart mixed email with image content

+From: Robert Burrell Donkin <robertburrelldonkin@blueyonder.co.uk>

+To: Robert Burrell Donkin <rdonkin@apache.org>

+Content-Type: multipart/mixed; boundary="=-tIdGYVstQJghyEDATnJ+"

+Date: Sun, 25 May 2008 15:38:13 +0100

+Message-Id: <1211726293.5772.10.camel@localhost>

+Mime-Version: 1.0

+X-Mailer: Evolution 2.12.3 

+X-Virus-Checked: Checked by ClamAV on apache.org

+X-Nonspam: None

+X-fetched-from: mail.xmlmapt.org

+X-Evolution-Source: imap://rob@thebes/

+

+

+--=-tIdGYVstQJghyEDATnJ+

+Content-Type: text/plain

+Content-Transfer-Encoding: 7bit

+

+Licensed to the Apache Software Foundation (ASF) under one

+or more contributor license agreements.  See the NOTICE file

+distributed with this work for additional information

+regarding copyright ownership.  The ASF licenses this file

+to you under the Apache License, Version 2.0 (the

+"License"); you may not use this file except in compliance

+with the License.  You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+ 

+Unless required by applicable law or agreed to in writing,

+software distributed under the License is distributed on an

+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+KIND, either express or implied.  See the License for the

+specific language governing permissions and limitations

+under the License.

+--=-tIdGYVstQJghyEDATnJ+

+Content-Disposition: attachment; filename=blob.png;

+   modification-date="Sun, 21 Jun 2008 15:32:18 +0000"; creation-date="Sat, 20 Jun 2008 10:15:09 +0000"; read-date="Mon, 22 Jun 2008 12:08:56 +0000";size=10234;

+Content-Type: image/png; name=blob.png

+Content-Transfer-Encoding: base64

+

+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL

+EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo

+IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ

+/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE

+E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF

+iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp

+rQAAAABJRU5ErkJggg==

+

+--=-tIdGYVstQJghyEDATnJ+

+Content-Disposition: attachment; filename=blob.png

+Content-Type: image/png; name=blob.png

+Content-Transfer-Encoding: base64

+

+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL

+EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo

+IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ

+/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE

+E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF

+iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp

+rQAAAABJRU5ErkJggg==

+

+--=-tIdGYVstQJghyEDATnJ+

+Content-Disposition: attachment; filename=rhubarb.txt

+Content-Type: text/plain; name=rhubarb.txt; charset=us-ascii

+Content-Language: en, en-US, en-CA

+Content-Transfer-Encoding: quoted-printable

+

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb

+

+--=-tIdGYVstQJghyEDATnJ+--

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/example.xml
new file mode 100644
index 0000000..ea35bd4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example.xml
@@ -0,0 +1,213 @@
+<message>

+<header>

+<field>

+Return-Path: &lt;robertburrelldonkin@blueyonder.co.uk&gt;</field>

+<field>

+Received: (qmail 18554 invoked from network); 25 May 2008 14:38:53 -0000</field>

+<field>

+Received: from unknown (HELO p3presmtp01-16.prod.phx3.secureserver.net)

+        ([208.109.80.165]) (envelope-sender &lt;rdonkin-owner@locus.apache.org&gt;) by

+        smtp20-01.prod.mesa1.secureserver.net (qmail-1.03) with SMTP for

+        &lt;asf@xmlmapt.org&gt;; 25 May 2008 14:38:53 -0000</field>

+<field>

+Received: (qmail 9751 invoked from network); 25 May 2008 14:38:53 -0000</field>

+<field>

+Received: from minotaur.apache.org ([140.211.11.9]) (envelope-sender

+        &lt;rdonkin-owner@locus.apache.org&gt;) by

+        p3presmtp01-16.prod.phx3.secureserver.net (qmail-ldap-1.03) with SMTP for

+        &lt;asf@xmlmapt.org&gt;; 25 May 2008 14:38:50 -0000</field>

+<field>

+Received: (qmail 46768 invoked by uid 1289); 25 May 2008 14:38:46 -0000</field>

+<field>

+Delivered-To: rdonkin@locus.apache.org</field>

+<field>

+Received: (qmail 46763 invoked from network); 25 May 2008 14:38:46 -0000</field>

+<field>

+Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by

+        minotaur.apache.org with SMTP; 25 May 2008 14:38:46 -0000</field>

+<field>

+Received: (qmail 61275 invoked by uid 500); 25 May 2008 14:38:48 -0000</field>

+<field>

+Delivered-To: apmail-rdonkin@apache.org</field>

+<field>

+Delivered-To: rob@localhost</field>

+<field>

+Delivered-To: rob@localhost</field>

+<field>

+Received: (qmail 61272 invoked by uid 99); 25 May 2008 14:38:48 -0000</field>

+<field>

+Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)

+        by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008 07:38:48 -0700</field>

+<field>

+X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS</field>

+<field>

+X-Spam-Check-By: apache.org</field>

+<field>

+Received-SPF: pass (athena.apache.org: domain of

+        robertburrelldonkin@blueyonder.co.uk designates 195.188.213.5 as permitted

+        sender)</field>

+<field>

+Received: from [195.188.213.5] (HELO smtp-out2.blueyonder.co.uk)

+        (195.188.213.5) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008

+        14:38:00 +0000</field>

+<field>

+Received: from [172.23.170.140] (helo=anti-virus02-07) by

+        smtp-out2.blueyonder.co.uk with smtp (Exim 4.52) id 1K0HMV-00087e-HY for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:15 +0100</field>

+<field>

+Received: from [82.38.65.6] (helo=[10.0.0.27]) by

+        asmtp-out5.blueyonder.co.uk with esmtpa (Exim 4.52) id 1K0HMU-0001A2-3q for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:14 +0100</field>

+<field>

+Subject: This is an example of a multipart mixed email with image content</field>

+<field>

+From: Robert Burrell Donkin &lt;robertburrelldonkin@blueyonder.co.uk&gt;</field>

+<field>

+To: Robert Burrell Donkin &lt;rdonkin@apache.org&gt;</field>

+<field>

+Content-Type: multipart/mixed; boundary="=-tIdGYVstQJghyEDATnJ+"</field>

+<field>

+Date: Sun, 25 May 2008 15:38:13 +0100</field>

+<field>

+Message-Id: &lt;1211726293.5772.10.camel@localhost&gt;</field>

+<field>

+Mime-Version: 1.0</field>

+<field>

+X-Mailer: Evolution 2.12.3 </field>

+<field>

+X-Virus-Checked: Checked by ClamAV on apache.org</field>

+<field>

+X-Nonspam: None</field>

+<field>

+X-fetched-from: mail.xmlmapt.org</field>

+<field>

+X-Evolution-Source: imap://rob@thebes/</field>

+</header>

+<multipart>

+<preamble>

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Licensed to the Apache Software Foundation (ASF) under one

+or more contributor license agreements.  See the NOTICE file

+distributed with this work for additional information

+regarding copyright ownership.  The ASF licenses this file

+to you under the Apache License, Version 2.0 (the

+"License"); you may not use this file except in compliance

+with the License.  You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+ 

+Unless required by applicable law or agreed to in writing,

+software distributed under the License is distributed on an

+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+KIND, either express or implied.  See the License for the

+specific language governing permissions and limitations

+under the License.</body>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Disposition: attachment; filename=blob.png;

+   modification-date="Sun, 21 Jun 2008 15:32:18 +0000"; creation-date="Sat, 20 Jun 2008 10:15:09 +0000"; read-date="Mon, 22 Jun 2008 12:08:56 +0000";size=10234;</field>

+<field>

+Content-Type: image/png; name=blob.png</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<body>

+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL

+EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo

+IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ

+/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE

+E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF

+iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp

+rQAAAABJRU5ErkJggg==

+

+</body>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Disposition: attachment; filename=blob.png</field>

+<field>

+Content-Type: image/png; name=blob.png</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<body>

+iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL

+EwAACxMBAJqcGAAAAAd0SU1FB9gFGQ4iJ99ufcYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo

+IEdJTVBXgQ4XAAAA0ElEQVQY02XMwUrDQBhF4XsnkyYhjWJaCloEN77/a/gERVwJLQiiNjYmbTqZ

+/7qIG/VsPziMTw+23Wj/ovZdMQJgViCvWNVusfa23djuUf2nugbnI2RynkWF5a2Fwdvrs7q9vhqE

+E2QAEIO6BhZBerUf6luMw49NyTR0OLw5kJD9sqk4Ipwc6GAREv5n5piXTDOQfy1JMSs8ZgXKq2kF

+iwDgEriEecnLlefFEmGAIvqD4ggJJNMM85qLtXfX9xYGuEQ+4/kIi0g88zlXd66++QaQDG5GPZyp

+rQAAAABJRU5ErkJggg==

+

+</body>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Disposition: attachment; filename=rhubarb.txt</field>

+<field>

+Content-Type: text/plain; name=rhubarb.txt; charset=us-ascii</field>

+<field>

+Content-Language: en, en-US, en-CA</field>

+<field>

+Content-Transfer-Encoding: quoted-printable</field>

+</header>

+<body>

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhu=

+barb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubar=

+b Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb R=

+hubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhub=

+arb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb=

+ Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rh=

+ubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhuba=

+rb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb =

+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb

+</body>

+</body-part>

+<epilogue>

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded.xml
new file mode 100644
index 0000000..9dad4e4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded.xml
@@ -0,0 +1,137 @@
+<message>

+<header>

+<field>

+Return-Path: &lt;robertburrelldonkin@blueyonder.co.uk&gt;</field>

+<field>

+Received: (qmail 18554 invoked from network); 25 May 2008 14:38:53 -0000</field>

+<field>

+Received: from unknown (HELO p3presmtp01-16.prod.phx3.secureserver.net)

+        ([208.109.80.165]) (envelope-sender &lt;rdonkin-owner@locus.apache.org&gt;) by

+        smtp20-01.prod.mesa1.secureserver.net (qmail-1.03) with SMTP for

+        &lt;asf@xmlmapt.org&gt;; 25 May 2008 14:38:53 -0000</field>

+<field>

+Received: (qmail 9751 invoked from network); 25 May 2008 14:38:53 -0000</field>

+<field>

+Received: from minotaur.apache.org ([140.211.11.9]) (envelope-sender

+        &lt;rdonkin-owner@locus.apache.org&gt;) by

+        p3presmtp01-16.prod.phx3.secureserver.net (qmail-ldap-1.03) with SMTP for

+        &lt;asf@xmlmapt.org&gt;; 25 May 2008 14:38:50 -0000</field>

+<field>

+Received: (qmail 46768 invoked by uid 1289); 25 May 2008 14:38:46 -0000</field>

+<field>

+Delivered-To: rdonkin@locus.apache.org</field>

+<field>

+Received: (qmail 46763 invoked from network); 25 May 2008 14:38:46 -0000</field>

+<field>

+Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by

+        minotaur.apache.org with SMTP; 25 May 2008 14:38:46 -0000</field>

+<field>

+Received: (qmail 61275 invoked by uid 500); 25 May 2008 14:38:48 -0000</field>

+<field>

+Delivered-To: apmail-rdonkin@apache.org</field>

+<field>

+Delivered-To: rob@localhost</field>

+<field>

+Delivered-To: rob@localhost</field>

+<field>

+Received: (qmail 61272 invoked by uid 99); 25 May 2008 14:38:48 -0000</field>

+<field>

+Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136)

+        by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008 07:38:48 -0700</field>

+<field>

+X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS</field>

+<field>

+X-Spam-Check-By: apache.org</field>

+<field>

+Received-SPF: pass (athena.apache.org: domain of

+        robertburrelldonkin@blueyonder.co.uk designates 195.188.213.5 as permitted

+        sender)</field>

+<field>

+Received: from [195.188.213.5] (HELO smtp-out2.blueyonder.co.uk)

+        (195.188.213.5) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 25 May 2008

+        14:38:00 +0000</field>

+<field>

+Received: from [172.23.170.140] (helo=anti-virus02-07) by

+        smtp-out2.blueyonder.co.uk with smtp (Exim 4.52) id 1K0HMV-00087e-HY for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:15 +0100</field>

+<field>

+Received: from [82.38.65.6] (helo=[10.0.0.27]) by

+        asmtp-out5.blueyonder.co.uk with esmtpa (Exim 4.52) id 1K0HMU-0001A2-3q for

+        rdonkin@apache.org; Sun, 25 May 2008 15:38:14 +0100</field>

+<field>

+Subject: This is an example of a multipart mixed email with image content</field>

+<field>

+From: Robert Burrell Donkin &lt;robertburrelldonkin@blueyonder.co.uk&gt;</field>

+<field>

+To: Robert Burrell Donkin &lt;rdonkin@apache.org&gt;</field>

+<field>

+Content-Type: multipart/mixed; boundary="=-tIdGYVstQJghyEDATnJ+"</field>

+<field>

+Date: Sun, 25 May 2008 15:38:13 +0100</field>

+<field>

+Message-Id: &lt;1211726293.5772.10.camel@localhost&gt;</field>

+<field>

+Mime-Version: 1.0</field>

+<field>

+X-Mailer: Evolution 2.12.3 </field>

+<field>

+X-Virus-Checked: Checked by ClamAV on apache.org</field>

+<field>

+X-Nonspam: None</field>

+<field>

+X-fetched-from: mail.xmlmapt.org</field>

+<field>

+X-Evolution-Source: imap://rob@thebes/</field>

+</header>

+<multipart>

+<preamble>

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="example_decoded_1_1.txt"/>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Disposition: attachment; filename=blob.png;

+   modification-date="Sun, 21 Jun 2008 15:32:18 +0000"; creation-date="Sat, 20 Jun 2008 10:15:09 +0000"; read-date="Mon, 22 Jun 2008 12:08:56 +0000";size=10234;</field>

+<field>

+Content-Type: image/png; name=blob.png</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<binary-body name="example_decoded_1_2.bin"/>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Disposition: attachment; filename=blob.png</field>

+<field>

+Content-Type: image/png; name=blob.png</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+</header>

+<binary-body name="example_decoded_1_3.bin"/>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Disposition: attachment; filename=rhubarb.txt</field>

+<field>

+Content-Type: text/plain; name=rhubarb.txt; charset=us-ascii</field>

+<field>

+Content-Language: en, en-US, en-CA</field>

+<field>

+Content-Transfer-Encoding: quoted-printable</field>

+</header>

+<text-body name="example_decoded_1_4.txt"/>

+</body-part>

+<epilogue>

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_1.txt
new file mode 100644
index 0000000..7217847
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_1.txt
@@ -0,0 +1,16 @@
+Licensed to the Apache Software Foundation (ASF) under one

+or more contributor license agreements.  See the NOTICE file

+distributed with this work for additional information

+regarding copyright ownership.  The ASF licenses this file

+to you under the Apache License, Version 2.0 (the

+"License"); you may not use this file except in compliance

+with the License.  You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+ 

+Unless required by applicable law or agreed to in writing,

+software distributed under the License is distributed on an

+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+KIND, either express or implied.  See the License for the

+specific language governing permissions and limitations

+under the License.
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_2.bin b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_2.bin
new file mode 100644
index 0000000..038bb87
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_2.bin
Binary files differ
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_3.bin b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_3.bin
new file mode 100644
index 0000000..038bb87
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_3.bin
Binary files differ
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_4.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_4.txt
new file mode 100644
index 0000000..6a9d4b9
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/example_decoded_1_4.txt
@@ -0,0 +1 @@
+Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb Rhubarb

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.msg
new file mode 100644
index 0000000..5abd15a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.msg
@@ -0,0 +1,36 @@
+Content-Type: multipart/mixed; boundary="boundary"

+

+preamble

+

+--boundary

+Content-Type: text/plain

+

+first part

+

+--boundary    

+Content-Type: text/plain

+

+from the rfc:

+================================

+encapsulation := delimiter transport-padding

+                      CRLF body-part

+================================

+and also

+================================

+"Composers MUST NOT generate non-zero length transport

+padding, but receivers MUST be able to handle padding

+added by message transports."

+================================

+

+second part have a start boundary ending with spaces

+and also have a boundary not at the beginning

+ --boundary

+... that should be ignored

+

+also a boundary with more data (a tab) shoud be ignored

+ --boundary	

+ 

+end of part

+

+--boundary--

+epilouge
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.out b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.out
new file mode 100644
index 0000000..47e06c0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.out
@@ -0,0 +1,36 @@
+Content-Type: multipart/mixed; boundary="boundary"

+

+preamble

+

+--boundary

+Content-Type: text/plain

+

+first part

+

+--boundary

+Content-Type: text/plain

+

+from the rfc:

+================================

+encapsulation := delimiter transport-padding

+                      CRLF body-part

+================================

+and also

+================================

+"Composers MUST NOT generate non-zero length transport

+padding, but receivers MUST be able to handle padding

+added by message transports."

+================================

+

+second part have a start boundary ending with spaces

+and also have a boundary not at the beginning

+ --boundary

+... that should be ignored

+

+also a boundary with more data (a tab) shoud be ignored

+ --boundary	

+ 

+end of part

+

+--boundary--

+epilouge
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.xml
new file mode 100644
index 0000000..e64d952
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries.xml
@@ -0,0 +1,51 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="boundary"</field>

+</header>

+<multipart>

+<preamble>

+preamble

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<body>

+first part

+</body>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<body>

+from the rfc:

+================================

+encapsulation := delimiter transport-padding

+                      CRLF body-part

+================================

+and also

+================================

+"Composers MUST NOT generate non-zero length transport

+padding, but receivers MUST be able to handle padding

+added by message transports."

+================================

+

+second part have a start boundary ending with spaces

+and also have a boundary not at the beginning

+ --boundary

+... that should be ignored

+

+also a boundary with more data (a tab) shoud be ignored

+ --boundary	

+ 

+end of part

+</body>

+</body-part>

+<epilogue>

+epilouge</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded.xml
new file mode 100644
index 0000000..3176945
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded.xml
@@ -0,0 +1,27 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="boundary"</field>

+</header>

+<multipart>

+<preamble>

+preamble

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<text-body name="intermediate-boundaries_decoded_1_1.txt"/>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<text-body name="intermediate-boundaries_decoded_1_2.txt"/>

+</body-part>

+<epilogue>

+epilouge</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded_1_1.txt
new file mode 100644
index 0000000..64d7434
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded_1_1.txt
@@ -0,0 +1 @@
+first part

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded_1_2.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded_1_2.txt
new file mode 100644
index 0000000..d81f4c9
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/intermediate-boundaries_decoded_1_2.txt
@@ -0,0 +1,21 @@
+from the rfc:

+================================

+encapsulation := delimiter transport-padding

+                      CRLF body-part

+================================

+and also

+================================

+"Composers MUST NOT generate non-zero length transport

+padding, but receivers MUST be able to handle padding

+added by message transports."

+================================

+

+second part have a start boundary ending with spaces

+and also have a boundary not at the beginning

+ --boundary

+... that should be ignored

+

+also a boundary with more data (a tab) shoud be ignored

+ --boundary	

+ 

+end of part

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.msg
new file mode 100644
index 0000000..31d324a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.msg
@@ -0,0 +1,10 @@
+Content-Type: multipart/mixed; boundary="boundary"

+

+--boundary

+Content-Type: text/plain

+

+This should be a text including the --boundary

+string and should not be parsed as multiple bodies

+

+--boundary--

+epilouge

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.out b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.out
new file mode 100644
index 0000000..324c8d6
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.out
@@ -0,0 +1,11 @@
+Content-Type: multipart/mixed; boundary="boundary"

+

+

+--boundary

+Content-Type: text/plain

+

+This should be a text including the --boundary

+string and should not be parsed as multiple bodies

+

+--boundary--

+epilouge

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.xml
new file mode 100644
index 0000000..c98284a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary.xml
@@ -0,0 +1,23 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="boundary"</field>

+</header>

+<multipart>

+<preamble>

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<body>

+This should be a text including the --boundary

+string and should not be parsed as multiple bodies

+</body>

+</body-part>

+<epilogue>

+epilouge

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary_decoded.xml
new file mode 100644
index 0000000..3ba7342
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary_decoded.xml
@@ -0,0 +1,20 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="boundary"</field>

+</header>

+<multipart>

+<preamble>

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<text-body name="misplaced-boundary_decoded_1_1.txt"/>

+</body-part>

+<epilogue>

+epilouge

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary_decoded_1_1.txt
new file mode 100644
index 0000000..89dab65
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/misplaced-boundary_decoded_1_1.txt
@@ -0,0 +1,2 @@
+This should be a text including the --boundary

+string and should not be parsed as multiple bodies

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.msg
new file mode 100644
index 0000000..361f826
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.msg
@@ -0,0 +1,16 @@
+Content-Type: multipart/mixed; boundary="outer-boundary"

+

+Outer preamble

+

+--outer-boundary

+Content-Type: text/plain

+

+Foo

+

+--outer-boundary

+Content-Type: multipart/alternative; boundary="inner-boundary"

+

+AAA

+

+--outer-boundary--

+Outer epilouge

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.out b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.out
new file mode 100644
index 0000000..c01344d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.out
@@ -0,0 +1,21 @@
+Content-Type: multipart/mixed; boundary="outer-boundary"

+

+Outer preamble

+

+--outer-boundary

+Content-Type: text/plain

+

+Foo

+

+--outer-boundary

+Content-Type: multipart/alternative; boundary="inner-boundary"

+

+AAA

+

+--inner-boundary

+

+

+--inner-boundary--

+

+--outer-boundary--

+Outer epilouge

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.xml
new file mode 100644
index 0000000..16259c0
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary.xml
@@ -0,0 +1,42 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="outer-boundary"</field>

+</header>

+<multipart>

+<preamble>

+Outer preamble

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<body>

+Foo

+</body>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Type: multipart/alternative; boundary="inner-boundary"</field>

+</header>

+<multipart>

+<preamble>

+AAA

+</preamble>

+<body-part>

+<header>

+</header>

+<body>

+</body>

+</body-part>

+<epilogue>

+</epilogue>

+</multipart>

+</body-part>

+<epilogue>

+Outer epilouge

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded.xml
new file mode 100644
index 0000000..c45c370
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded.xml
@@ -0,0 +1,39 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="outer-boundary"</field>

+</header>

+<multipart>

+<preamble>

+Outer preamble

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain</field>

+</header>

+<text-body name="missing-inner-boundary_decoded_1_1.txt"/>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Type: multipart/alternative; boundary="inner-boundary"</field>

+</header>

+<multipart>

+<preamble>

+AAA

+</preamble>

+<body-part>

+<header>

+</header>

+<text-body name="missing-inner-boundary_decoded_1_2_1.txt"/>

+</body-part>

+<epilogue>

+</epilogue>

+</multipart>

+</body-part>

+<epilogue>

+Outer epilouge

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded_1_1.txt
new file mode 100644
index 0000000..554c75e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded_1_1.txt
@@ -0,0 +1 @@
+Foo

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded_1_2_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded_1_2_1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/missing-inner-boundary_decoded_1_2_1.txt
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.msg
new file mode 100644
index 0000000..d21fae4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.msg
@@ -0,0 +1,6 @@
+Mime-Version: 1.0

+Subject: subject

+Content-Type: text/plain; charset="iso-8859-15"

+Content-Transfer-Encoding: quoted-printable

+

+7bit content with euro =A4 symbol=20

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.out b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.out
new file mode 100644
index 0000000..d21fae4
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.out
@@ -0,0 +1,6 @@
+Mime-Version: 1.0

+Subject: subject

+Content-Type: text/plain; charset="iso-8859-15"

+Content-Transfer-Encoding: quoted-printable

+

+7bit content with euro =A4 symbol=20

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.xml
new file mode 100644
index 0000000..1414303
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body.xml
@@ -0,0 +1,15 @@
+<message>

+<header>

+<field>

+Mime-Version: 1.0</field>

+<field>

+Subject: subject</field>

+<field>

+Content-Type: text/plain; charset="iso-8859-15"</field>

+<field>

+Content-Transfer-Encoding: quoted-printable</field>

+</header>

+<body>

+7bit content with euro =A4 symbol=20

+</body>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body_decoded.xml
new file mode 100644
index 0000000..c7fe1ff
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body_decoded.xml
@@ -0,0 +1,13 @@
+<message>

+<header>

+<field>

+Mime-Version: 1.0</field>

+<field>

+Subject: subject</field>

+<field>

+Content-Type: text/plain; charset="iso-8859-15"</field>

+<field>

+Content-Transfer-Encoding: quoted-printable</field>

+</header>

+<text-body name="qp-body_decoded_1.txt"/>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body_decoded_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body_decoded_1.txt
new file mode 100644
index 0000000..162acd2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/qp-body_decoded_1.txt
@@ -0,0 +1 @@
+7bit content with euro ¤ symbol 

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.msg
new file mode 100644
index 0000000..2c74f93
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.msg
@@ -0,0 +1,5 @@
+Content-Type: text/plain; charset="US-ASCII"; name==?koi8-r?B?89DJ08/LLmRvYw==?=

+Content-Disposition: attachment; filename==?koi8-r?B?89DJ08/LLmRvYw==?=

+Subject: A simple subject

+

+A simple body.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.out b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.out
new file mode 100644
index 0000000..2c74f93
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.out
@@ -0,0 +1,5 @@
+Content-Type: text/plain; charset="US-ASCII"; name==?koi8-r?B?89DJ08/LLmRvYw==?=

+Content-Disposition: attachment; filename==?koi8-r?B?89DJ08/LLmRvYw==?=

+Subject: A simple subject

+

+A simple body.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.xml
new file mode 100644
index 0000000..43a727e
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers.xml
@@ -0,0 +1,13 @@
+<message>

+<header>

+<field>

+Content-Type: text/plain; charset="US-ASCII"; name==?koi8-r?B?89DJ08/LLmRvYw==?=</field>

+<field>

+Content-Disposition: attachment; filename==?koi8-r?B?89DJ08/LLmRvYw==?=</field>

+<field>

+Subject: A simple subject</field>

+</header>

+<body>

+A simple body.

+</body>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers_decoded.xml
new file mode 100644
index 0000000..aa64b64
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers_decoded.xml
@@ -0,0 +1,11 @@
+<message>

+<header>

+<field>

+Content-Type: text/plain; charset="US-ASCII"; name==?koi8-r?B?89DJ08/LLmRvYw==?=</field>

+<field>

+Content-Disposition: attachment; filename==?koi8-r?B?89DJ08/LLmRvYw==?=</field>

+<field>

+Subject: A simple subject</field>

+</header>

+<text-body name="russian-headers_decoded_1.txt"/>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers_decoded_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers_decoded_1.txt
new file mode 100644
index 0000000..f4812b9
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/russian-headers_decoded_1.txt
@@ -0,0 +1 @@
+A simple body.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.msg
new file mode 100644
index 0000000..5ee0dd5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.msg
@@ -0,0 +1,43 @@
+Date: Fri, 27 Apr 2007 16:08:23 +0200

+From: Foo Bar <bar@example.com>

+MIME-Version: 1.0

+To:  foo@example.com

+Subject: Here is the attachment I was waiting for.

+Content-Type: multipart/mixed;

+ boundary="------------090404080405080108000909"

+

+This is a multi-part message in MIME format.

+--------------090404080405080108000909

+Content-Type: text/plain; charset=ISO-8859-15

+Content-Transfer-Encoding: 7bit

+

+Body.

+

+--------------090404080405080108000909

+Content-Type: application/octet-stream;

+ name="data.bin"

+Content-Transfer-Encoding: base64

+Content-Disposition: attachment;

+ filename="data.bin"

+

+lLzmyQjBC2gw/hiUrcy/DDI5K6CBqFSs4NKCF67G5XBzOnSInWpZ+9Uv9IxFpz8rf871xAE+

++y0ZYES9LXDdP12svxsJ4hRsekH2HJ953Kglb3hxko7LlPlxeDX15FKH0VBE8Ggr4RbwoP+c

+mkyyhKyaiV95ycRzRd5ozVDGhmW/eQIZgw3nYJOt99vyPxolkHD8PLevmx4PTteIO4hIWjHG

+XtKCTNwBG0z4cW3EOHWxsvo5v6JUEueDaxfFWKrA/MWP2TkYREXMj+q0XC4MpKZgIjqRL/9E

+s6gqpJTb4eyYL6FBdgrNeLqDQ5ozgu1zaQi9+yuoCABIHKCEPv32W+9Wt/MjMqCnKdk+Zdsw

+ZBna0Fq/168oqKh0S++trpgndHvWZWojNY+rDqnl5o3T9IvTgTuG8IHPSxUODbWFy1vim+jU

+eGNpCfko6DGo5oBCKzg5BTlz2kAED6F1X6/a+w0/9zGJZJ9Tyg6fb8LE7OwDFp1pH99x6SgR

+xa+IFHoXhbjRzkRi/ZRZKrqm4jxvhFTXlx9w70SL0GawHUwuNOgEUKJM75ADmDEEtRB0pQ8S

+RPoKn/b1RLGQPsvHzcqtSJljgbMMBmoiBFkAnzopnVn1RJfBzI6x9YcXtNqtJCTXdHzPg4D+

+WhwkCB0AF7W8EoVqvmlP2g0vAdPz4gR8+I6AFdGQtC52CMhX/1mHAeTjDCnuvTzZvKrACcVB

+9Ea12w10KLYbsgAr2+2vfAdiLUdUZDKHPPtWC+lSrvkTJtivU+YOSw7PCkWF7BIC7pTdp7Wu

+tqGCmVo0eHKfJxXcpkH++9ALeAQ8tfQw9K20JJW18fSAw/hs8fxs5FWjhNpYpUvQlqznN98K

+/pnaXQo373NufYHy1+yT3sSVEwBbClv7yOjrYrmyRe6ojw+ZxXziWk8r+VkFpotwvgW41vOu

+vkhd94rzr1Mj7WNEssTrJOQC5Uda2DPZkHgxBbZch2ru65Jmivr493iTF157c6MZhJUSW+P5

+Xd+WoDrUwzcpMx7QdyZaNSPVsL7uD4xOKoqm4OcdyzEj4qqDvBLA0TJ8sQ4Fp0A5h7nNTuoU

+vxKMan0J4rRKc7T4eswuLEaTPCDtKpsmlTS+rG4jPaCOlPM++qrI6VMgJBZOL/zG7mLub/IY

+KmU6Svelyk91XQF23dhbSqlLjeLlGjwtlHhqRuFASVIgIqcxbsrxa6CSmTrHmxr0NU5hmEWb

+lBPvZwYZhZMu2c/yTirvknIijyTRjFmgwpB73uJHv0oQotC6myXTGNCc0MihBMOsDQs3Fhsl

+JFQcH6VA0bze/FSZoGi+sM90lyrufQngenV1EVptFBx5DQYWEWXKOi2ZS6JQGYRh1R+EXA==

+--------------090404080405080108000909--

+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.out b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.out
new file mode 100644
index 0000000..8d2595f
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.out
@@ -0,0 +1,43 @@
+Date: Fri, 27 Apr 2007 16:08:23 +0200

+From: Foo Bar <bar@example.com>

+MIME-Version: 1.0

+To:  foo@example.com

+Subject: Here is the attachment I was waiting for.

+Content-Type: multipart/mixed;

+ boundary="------------090404080405080108000909"

+

+This is a multi-part message in MIME format.

+--------------090404080405080108000909

+Content-Type: text/plain; charset=ISO-8859-15

+Content-Transfer-Encoding: 7bit

+

+Body.

+

+--------------090404080405080108000909

+Content-Type: application/octet-stream;

+ name="data.bin"

+Content-Transfer-Encoding: base64

+Content-Disposition: attachment;

+ filename="data.bin"

+

+lLzmyQjBC2gw/hiUrcy/DDI5K6CBqFSs4NKCF67G5XBzOnSInWpZ+9Uv9IxFpz8rf871xAE++y0Z

+YES9LXDdP12svxsJ4hRsekH2HJ953Kglb3hxko7LlPlxeDX15FKH0VBE8Ggr4RbwoP+cmkyyhKya

+iV95ycRzRd5ozVDGhmW/eQIZgw3nYJOt99vyPxolkHD8PLevmx4PTteIO4hIWjHGXtKCTNwBG0z4

+cW3EOHWxsvo5v6JUEueDaxfFWKrA/MWP2TkYREXMj+q0XC4MpKZgIjqRL/9Es6gqpJTb4eyYL6FB

+dgrNeLqDQ5ozgu1zaQi9+yuoCABIHKCEPv32W+9Wt/MjMqCnKdk+ZdswZBna0Fq/168oqKh0S++t

+rpgndHvWZWojNY+rDqnl5o3T9IvTgTuG8IHPSxUODbWFy1vim+jUeGNpCfko6DGo5oBCKzg5BTlz

+2kAED6F1X6/a+w0/9zGJZJ9Tyg6fb8LE7OwDFp1pH99x6SgRxa+IFHoXhbjRzkRi/ZRZKrqm4jxv

+hFTXlx9w70SL0GawHUwuNOgEUKJM75ADmDEEtRB0pQ8SRPoKn/b1RLGQPsvHzcqtSJljgbMMBmoi

+BFkAnzopnVn1RJfBzI6x9YcXtNqtJCTXdHzPg4D+WhwkCB0AF7W8EoVqvmlP2g0vAdPz4gR8+I6A

+FdGQtC52CMhX/1mHAeTjDCnuvTzZvKrACcVB9Ea12w10KLYbsgAr2+2vfAdiLUdUZDKHPPtWC+lS

+rvkTJtivU+YOSw7PCkWF7BIC7pTdp7WutqGCmVo0eHKfJxXcpkH++9ALeAQ8tfQw9K20JJW18fSA

+w/hs8fxs5FWjhNpYpUvQlqznN98K/pnaXQo373NufYHy1+yT3sSVEwBbClv7yOjrYrmyRe6ojw+Z

+xXziWk8r+VkFpotwvgW41vOuvkhd94rzr1Mj7WNEssTrJOQC5Uda2DPZkHgxBbZch2ru65Jmivr4

+93iTF157c6MZhJUSW+P5Xd+WoDrUwzcpMx7QdyZaNSPVsL7uD4xOKoqm4OcdyzEj4qqDvBLA0TJ8

+sQ4Fp0A5h7nNTuoUvxKMan0J4rRKc7T4eswuLEaTPCDtKpsmlTS+rG4jPaCOlPM++qrI6VMgJBZO

+L/zG7mLub/IYKmU6Svelyk91XQF23dhbSqlLjeLlGjwtlHhqRuFASVIgIqcxbsrxa6CSmTrHmxr0

+NU5hmEWblBPvZwYZhZMu2c/yTirvknIijyTRjFmgwpB73uJHv0oQotC6myXTGNCc0MihBMOsDQs3

+FhslJFQcH6VA0bze/FSZoGi+sM90lyrufQngenV1EVptFBx5DQYWEWXKOi2ZS6JQGYRh1R+EXA==

+

+--------------090404080405080108000909--

+

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.xml
new file mode 100644
index 0000000..ae9ba68
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment.xml
@@ -0,0 +1,67 @@
+<message>

+<header>

+<field>

+Date: Fri, 27 Apr 2007 16:08:23 +0200</field>

+<field>

+From: Foo Bar &lt;bar@example.com&gt;</field>

+<field>

+MIME-Version: 1.0</field>

+<field>

+To:  foo@example.com</field>

+<field>

+Subject: Here is the attachment I was waiting for.</field>

+<field>

+Content-Type: multipart/mixed;

+ boundary="------------090404080405080108000909"</field>

+</header>

+<multipart>

+<preamble>

+This is a multi-part message in MIME format.</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=ISO-8859-15</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Body.

+</body>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Type: application/octet-stream;

+ name="data.bin"</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+<field>

+Content-Disposition: attachment;

+ filename="data.bin"</field>

+</header>

+<body>

+lLzmyQjBC2gw/hiUrcy/DDI5K6CBqFSs4NKCF67G5XBzOnSInWpZ+9Uv9IxFpz8rf871xAE+

++y0ZYES9LXDdP12svxsJ4hRsekH2HJ953Kglb3hxko7LlPlxeDX15FKH0VBE8Ggr4RbwoP+c

+mkyyhKyaiV95ycRzRd5ozVDGhmW/eQIZgw3nYJOt99vyPxolkHD8PLevmx4PTteIO4hIWjHG

+XtKCTNwBG0z4cW3EOHWxsvo5v6JUEueDaxfFWKrA/MWP2TkYREXMj+q0XC4MpKZgIjqRL/9E

+s6gqpJTb4eyYL6FBdgrNeLqDQ5ozgu1zaQi9+yuoCABIHKCEPv32W+9Wt/MjMqCnKdk+Zdsw

+ZBna0Fq/168oqKh0S++trpgndHvWZWojNY+rDqnl5o3T9IvTgTuG8IHPSxUODbWFy1vim+jU

+eGNpCfko6DGo5oBCKzg5BTlz2kAED6F1X6/a+w0/9zGJZJ9Tyg6fb8LE7OwDFp1pH99x6SgR

+xa+IFHoXhbjRzkRi/ZRZKrqm4jxvhFTXlx9w70SL0GawHUwuNOgEUKJM75ADmDEEtRB0pQ8S

+RPoKn/b1RLGQPsvHzcqtSJljgbMMBmoiBFkAnzopnVn1RJfBzI6x9YcXtNqtJCTXdHzPg4D+

+WhwkCB0AF7W8EoVqvmlP2g0vAdPz4gR8+I6AFdGQtC52CMhX/1mHAeTjDCnuvTzZvKrACcVB

+9Ea12w10KLYbsgAr2+2vfAdiLUdUZDKHPPtWC+lSrvkTJtivU+YOSw7PCkWF7BIC7pTdp7Wu

+tqGCmVo0eHKfJxXcpkH++9ALeAQ8tfQw9K20JJW18fSAw/hs8fxs5FWjhNpYpUvQlqznN98K

+/pnaXQo373NufYHy1+yT3sSVEwBbClv7yOjrYrmyRe6ojw+ZxXziWk8r+VkFpotwvgW41vOu

+vkhd94rzr1Mj7WNEssTrJOQC5Uda2DPZkHgxBbZch2ru65Jmivr493iTF157c6MZhJUSW+P5

+Xd+WoDrUwzcpMx7QdyZaNSPVsL7uD4xOKoqm4OcdyzEj4qqDvBLA0TJ8sQ4Fp0A5h7nNTuoU

+vxKMan0J4rRKc7T4eswuLEaTPCDtKpsmlTS+rG4jPaCOlPM++qrI6VMgJBZOL/zG7mLub/IY

+KmU6Svelyk91XQF23dhbSqlLjeLlGjwtlHhqRuFASVIgIqcxbsrxa6CSmTrHmxr0NU5hmEWb

+lBPvZwYZhZMu2c/yTirvknIijyTRjFmgwpB73uJHv0oQotC6myXTGNCc0MihBMOsDQs3Fhsl

+JFQcH6VA0bze/FSZoGi+sM90lyrufQngenV1EVptFBx5DQYWEWXKOi2ZS6JQGYRh1R+EXA==</body>

+</body-part>

+<epilogue>

+

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded.xml
new file mode 100644
index 0000000..b3849a5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded.xml
@@ -0,0 +1,46 @@
+<message>

+<header>

+<field>

+Date: Fri, 27 Apr 2007 16:08:23 +0200</field>

+<field>

+From: Foo Bar &lt;bar@example.com&gt;</field>

+<field>

+MIME-Version: 1.0</field>

+<field>

+To:  foo@example.com</field>

+<field>

+Subject: Here is the attachment I was waiting for.</field>

+<field>

+Content-Type: multipart/mixed;

+ boundary="------------090404080405080108000909"</field>

+</header>

+<multipart>

+<preamble>

+This is a multi-part message in MIME format.</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=ISO-8859-15</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="simple-attachment_decoded_1_1.txt"/>

+</body-part>

+<body-part>

+<header>

+<field>

+Content-Type: application/octet-stream;

+ name="data.bin"</field>

+<field>

+Content-Transfer-Encoding: base64</field>

+<field>

+Content-Disposition: attachment;

+ filename="data.bin"</field>

+</header>

+<binary-body name="simple-attachment_decoded_1_2.bin"/>

+</body-part>

+<epilogue>

+

+</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded_1_1.txt
new file mode 100644
index 0000000..5eb4b27
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded_1_1.txt
@@ -0,0 +1 @@
+Body.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded_1_2.bin b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded_1_2.bin
new file mode 100644
index 0000000..499f48c
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/simple-attachment_decoded_1_2.bin
Binary files differ
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.msg
new file mode 100644
index 0000000..f82c8bc
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.msg
@@ -0,0 +1,15 @@
+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "

+

+multipart

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  --

+epilogue
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.out b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.out
new file mode 100644
index 0000000..f82c8bc
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.out
@@ -0,0 +1,15 @@
+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "

+

+multipart

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  --

+epilogue
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.xml
new file mode 100644
index 0000000..f0fa976
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary.xml
@@ -0,0 +1,27 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "</field>

+</header>

+<multipart>

+<preamble>

+multipart

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+</body>

+</body-part>

+<epilogue>

+epilogue</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary_decoded.xml
new file mode 100644
index 0000000..83e391f
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary_decoded.xml
@@ -0,0 +1,22 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "</field>

+</header>

+<multipart>

+<preamble>

+multipart

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="very-long-boundary_decoded_1_1.txt"/>

+</body-part>

+<epilogue>

+epilogue</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary_decoded_1_1.txt
new file mode 100644
index 0000000..764b26d
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-long-boundary_decoded_1_1.txt
@@ -0,0 +1,4 @@
+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.msg
new file mode 100644
index 0000000..d4bbbd5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.msg
@@ -0,0 +1,15 @@
+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "

+

+multipart

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  --

+epilogue
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.out b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.out
new file mode 100644
index 0000000..d4bbbd5
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.out
@@ -0,0 +1,15 @@
+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "

+

+multipart

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  --

+epilogue
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.xml
new file mode 100644
index 0000000..0877ac2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary.xml
@@ -0,0 +1,27 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "</field>

+</header>

+<multipart>

+<preamble>

+multipart

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+</body>

+</body-part>

+<epilogue>

+epilogue</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary_decoded.xml
new file mode 100644
index 0000000..5d5b7ed
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary_decoded.xml
@@ -0,0 +1,22 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "</field>

+</header>

+<multipart>

+<preamble>

+multipart

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="very-very-long-boundary_decoded_1_1.txt"/>

+</body-part>

+<epilogue>

+epilogue</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary_decoded_1_1.txt
new file mode 100644
index 0000000..e27d445
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/very-very-long-boundary_decoded_1_1.txt
@@ -0,0 +1,4 @@
+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.msg b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.msg
new file mode 100644
index 0000000..f2dd0c2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.msg
@@ -0,0 +1,15 @@
+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "

+

+multipart

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  --

+epilogue
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.out b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.out
new file mode 100644
index 0000000..f2dd0c2
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.out
@@ -0,0 +1,15 @@
+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "

+

+multipart

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  

+Content-Type: text/plain; charset=us-ascii

+Content-Transfer-Encoding: 7bit

+

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  --

+epilogue
\ No newline at end of file
diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.xml
new file mode 100644
index 0000000..895cb7a
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary.xml
@@ -0,0 +1,27 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "</field>

+</header>

+<multipart>

+<preamble>

+multipart

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<body>

+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

+</body>

+</body-part>

+<epilogue>

+epilogue</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary_decoded.xml b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary_decoded.xml
new file mode 100644
index 0000000..59eaea1
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary_decoded.xml
@@ -0,0 +1,22 @@
+<message>

+<header>

+<field>

+Content-Type: multipart/mixed; boundary="0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=?  "</field>

+</header>

+<multipart>

+<preamble>

+multipart

+</preamble>

+<body-part>

+<header>

+<field>

+Content-Type: text/plain; charset=us-ascii</field>

+<field>

+Content-Transfer-Encoding: 7bit</field>

+</header>

+<text-body name="weird-boundary_decoded_1_1.txt"/>

+</body-part>

+<epilogue>

+epilogue</epilogue>

+</multipart>

+</message>

diff --git a/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary_decoded_1_1.txt b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary_decoded_1_1.txt
new file mode 100644
index 0000000..759e6ad
--- /dev/null
+++ b/apache-mime4j-0.6/src/test/resources/testmsgs/weird-boundary_decoded_1_1.txt
@@ -0,0 +1,4 @@
+Text body

+--0123456789abcdefghijklmnopqrstuvwxyzABCDEFLMNOPRSTUVWXYZ'()+_,-./:=? 

+The above line is similar to the boundary but miss a final space, so it

+should be part of the body.

diff --git a/apache-mime4j-0.6/stage/commons-io/jars/commons-io-1.2.jar b/apache-mime4j-0.6/stage/commons-io/jars/commons-io-1.2.jar
new file mode 100644
index 0000000..b2867cd
--- /dev/null
+++ b/apache-mime4j-0.6/stage/commons-io/jars/commons-io-1.2.jar
Binary files differ
diff --git a/apache-mime4j-0.6/stage/commons-io/poms/commons-io-1.2.pom b/apache-mime4j-0.6/stage/commons-io/poms/commons-io-1.2.pom
new file mode 100644
index 0000000..30d7e34
--- /dev/null
+++ b/apache-mime4j-0.6/stage/commons-io/poms/commons-io-1.2.pom
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>commons-io</groupId>
+  <artifactId>commons-io</artifactId>
+  <name>IO</name>
+  <version>1.2</version>
+  <description>Commons-IO contains utility classes, stream implementations, file filters, and endian classes.</description>
+  <url>http://jakarta.apache.org/commons/io/</url>
+  <issueManagement>
+    <url>http://issues.apache.org/bugzilla/</url>
+  </issueManagement>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <configuration>
+          <address>commons-dev@jakarta.apache.org</address>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2002</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Commons Dev List</name>
+      <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+      <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+    </mailingList>
+    <mailingList>
+      <name>Commons User List</name>
+      <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+      <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+    </mailingList>
+  </mailingLists>
+  <developers>
+    <developer>
+      <id>sanders</id>
+      <name>Scott Sanders</name>
+      <email>sanders@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dion</id>
+      <name>dIon Gillard</name>
+      <email>dion@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>nicolaken</id>
+      <name>Nicola Ken Barozzi</name>
+      <email>nicolaken@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bayard</id>
+      <name>Henri Yandell</name>
+      <email>bayard@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>scolebourne</id>
+      <name>Stephen Colebourne</name>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+      <timezone>0</timezone>
+    </developer>
+    <developer>
+      <id>jeremias</id>
+      <name>Jeremias Maerki</name>
+      <email>jeremias@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>matth</id>
+      <name>Matthew Hawthorne</name>
+      <email>matth@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>martinc</id>
+      <name>Martin Cooper</name>
+      <email>martinc@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>roxspring</id>
+      <name>Rob Oxspring</name>
+      <email>roxspring@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <contributors>
+    <contributor>
+      <name>Rahul Akolkar</name>
+    </contributor>
+    <contributor>
+      <name>Jason Anderson</name>
+    </contributor>
+    <contributor>
+      <name>Nathan Beyer</name>
+    </contributor>
+    <contributor>
+      <name>Chris Eldredge</name>
+    </contributor>
+    <contributor>
+      <name>Jim Harrington</name>
+    </contributor>
+    <contributor>
+      <name>Thomas Ledoux</name>
+    </contributor>
+    <contributor>
+      <name>Andy Lehane</name>
+    </contributor>
+    <contributor>
+      <name>Marcelo Liberato</name>
+    </contributor>
+    <contributor>
+      <name>Alban Peignier</name>
+      <email>alban.peignier at free.fr</email>
+    </contributor>
+    <contributor>
+      <name>Niall Pemberton</name>
+    </contributor>
+    <contributor>
+      <name>Ian Springer</name>
+    </contributor>
+    <contributor>
+      <name>Masato Tezuka</name>
+    </contributor>
+    <contributor>
+      <name>Frank W. Zammetti</name>
+    </contributor>
+  </contributors>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>/LICENSE.txt</url>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/commons/proper/io/trunk</connection>
+    <url>http://svn.apache.org/repos/asf/jakarta/commons/proper/io/trunk</url>
+  </scm>
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://jakarta.apache.org</url>
+  </organization>
+  <build>
+    <sourceDirectory>src/java</sourceDirectory>
+    <testSourceDirectory>src/test</testSourceDirectory>
+    <resources>
+      <resource>
+        <targetPath>META-INF</targetPath>
+        <directory>.</directory>
+        <includes>
+          <include>NOTICE.txt</include>
+        </includes>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <includes>
+            <include>**/*Test*</include>
+          </includes>
+          <excludes>
+            <exclude>**/*AbstractTestCase*</exclude>
+            <exclude>**/AllIOTestSuite*</exclude>
+            <exclude>**/PackageTestSuite*</exclude>
+            <exclude>**/testtools/**</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>maven-plugins</groupId>
+        <artifactId>maven-cobertura-plugin</artifactId>
+        <version>1.1.1</version>
+        <configuration>
+          <scope>test</scope>
+          <comment>Required only for generating test coverage reports.</comment>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <repository>
+      <id>default</id>
+      <name>Default Repository</name>
+      <url>file:///www/jakarta.apache.org/builds/jakarta-commons/io/</url>
+    </repository>
+    <site>
+      <id>default</id>
+      <name>Default Site</name>
+      <url>scp://people.apache.org//www/jakarta.apache.org/commons/io/</url>
+    </site>
+    <status>converted</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/commons-logging/jars/commons-logging-1.1.jar b/apache-mime4j-0.6/stage/commons-logging/jars/commons-logging-1.1.jar
new file mode 100644
index 0000000..2ff9bbd
--- /dev/null
+++ b/apache-mime4j-0.6/stage/commons-logging/jars/commons-logging-1.1.jar
Binary files differ
diff --git a/apache-mime4j-0.6/stage/commons-logging/poms/commons-logging-1.1.pom b/apache-mime4j-0.6/stage/commons-logging/poms/commons-logging-1.1.pom
new file mode 100644
index 0000000..b1ea16f
--- /dev/null
+++ b/apache-mime4j-0.6/stage/commons-logging/poms/commons-logging-1.1.pom
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>commons-logging</groupId>
+  <artifactId>commons-logging</artifactId>
+  <name>Logging</name>
+  <version>1.1</version>
+  <description>Commons Logging is a thin adapter allowing configurable bridging to other,
+    well known logging systems.</description>
+  <url>http://jakarta.apache.org/commons/${pom.artifactId.substring(8)}/</url>
+  <issueManagement>
+    <url>http://issues.apache.org/bugzilla/</url>
+  </issueManagement>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <configuration>
+          <address>commons-dev@jakarta.apache.org</address>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Commons Dev List</name>
+      <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+      <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/jakarta-commons-dev/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Commons User List</name>
+      <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+      <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/jakarta-commons-user/</archive>
+    </mailingList>
+  </mailingLists>
+  <developers>
+    <developer>
+      <id>morgand</id>
+      <name>Morgan Delagrange</name>
+      <email>morgand at apache dot org</email>
+      <organization>Apache</organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>rwaldhoff</id>
+      <name>Rodney Waldhoff</name>
+      <email>rwaldhoff at apache org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>craigmcc</id>
+      <name>Craig McClanahan</name>
+      <email>craigmcc at apache org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>sanders</id>
+      <name>Scott Sanders</name>
+      <email>sanders at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>rdonkin</id>
+      <name>Robert Burrell Donkin</name>
+      <email>rdonkin at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>donaldp</id>
+      <name>Peter Donald</name>
+      <email>donaldp at apache dot org</email>
+      <organization></organization>
+    </developer>
+    <developer>
+      <id>costin</id>
+      <name>Costin Manolache</name>
+      <email>costin at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>rsitze</id>
+      <name>Richard Sitze</name>
+      <email>rsitze at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>baliuka</id>
+      <name>Juozas Baliuka</name>
+      <email>baliuka@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>skitching</id>
+      <name>Simon Kitching</name>
+      <email>skitching@apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>dennisl</id>
+      <name>Dennis Lundberg</name>
+      <email>dennisl@apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>bstansberry</id>
+      <name>Brian Stansberry</name>
+    </developer>
+  </developers>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>/LICENSE.txt</url>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/jakarta/commons/proper/${pom.artifactId.substring(8)}/trunk</connection>
+    <url>http://svn.apache.org/repos/asf/jakarta/commons/proper/${pom.artifactId.substring(8)}/trunk</url>
+  </scm>
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://jakarta.apache.org</url>
+  </organization>
+  <build>
+    <sourceDirectory>src/java</sourceDirectory>
+    <testSourceDirectory>src/test</testSourceDirectory>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <includes>
+            <include>**/AvalonLoggerTest.java</include>
+          </includes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-xdoc-plugin</artifactId>
+        <version>1.9.2</version>
+        <configuration>
+          <comment>&lt;strong>Site Only&lt;/strong> - v1.9.2 (minimum)</comment>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.12</version>
+    </dependency>
+    <dependency>
+      <groupId>logkit</groupId>
+      <artifactId>logkit</artifactId>
+      <version>1.0.1</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>avalon-framework</groupId>
+      <artifactId>avalon-framework</artifactId>
+      <version>4.1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.3</version>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <repository>
+      <id>default</id>
+      <name>Default Repository</name>
+      <url>file:///www/jakarta.apache.org/builds/jakarta-commons/${pom.artifactId.substring(8)}/</url>
+    </repository>
+    <site>
+      <id>default</id>
+      <name>Default Site</name>
+      <url>scp://cvs.apache.org//www/jakarta.apache.org/commons/${pom.artifactId.substring(8)}/</url>
+    </site>
+    <status>converted</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/junit/jars/junit-3.8.1.jar b/apache-mime4j-0.6/stage/junit/jars/junit-3.8.1.jar
new file mode 100644
index 0000000..674d71e
--- /dev/null
+++ b/apache-mime4j-0.6/stage/junit/jars/junit-3.8.1.jar
Binary files differ
diff --git a/apache-mime4j-0.6/stage/junit/poms/junit-3.8.1.pom b/apache-mime4j-0.6/stage/junit/poms/junit-3.8.1.pom
new file mode 100644
index 0000000..c724642
--- /dev/null
+++ b/apache-mime4j-0.6/stage/junit/poms/junit-3.8.1.pom
@@ -0,0 +1,33 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.    
+  -->
+  <modelVersion>4.0.0</modelVersion>

+  <groupId>junit</groupId>
+  <artifactId>junit</artifactId>
+  <name>JUnit</name>

+  <version>3.8.1</version>

+  <packaging>jar</packaging>

+  <url>http://www.junit.org</url>

+  <licenses>
+    <license>
+      <name>CPL v1.0</name>
+      <url>http://junit.sourceforge.net/cpl-v10.html</url>
+    </license>
+  </licenses>
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/log4j/jars/log4j-1.2.14.jar b/apache-mime4j-0.6/stage/log4j/jars/log4j-1.2.14.jar
new file mode 100644
index 0000000..6251307
--- /dev/null
+++ b/apache-mime4j-0.6/stage/log4j/jars/log4j-1.2.14.jar
Binary files differ
diff --git a/apache-mime4j-0.6/stage/log4j/poms/log4j-1.2.14.pom b/apache-mime4j-0.6/stage/log4j/poms/log4j-1.2.14.pom
new file mode 100644
index 0000000..a5c9622
--- /dev/null
+++ b/apache-mime4j-0.6/stage/log4j/poms/log4j-1.2.14.pom
Binary files differ
diff --git a/apache-mime4j-0.6/stage/org.apache.james/jars/maven-skin-1.1.jar b/apache-mime4j-0.6/stage/org.apache.james/jars/maven-skin-1.1.jar
new file mode 100644
index 0000000..99d274e
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/jars/maven-skin-1.1.jar
Binary files differ
diff --git a/apache-mime4j-0.6/stage/org.apache.james/poms/james-parent-1.1.pom b/apache-mime4j-0.6/stage/org.apache.james/poms/james-parent-1.1.pom
new file mode 100644
index 0000000..14b8dea
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/poms/james-parent-1.1.pom
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.    
+  -->
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.james</groupId>
+  <artifactId>james-parent</artifactId>
+  <name>Apache JAMES Parent POM</name>
+  <version>1.1</version>
+  <description>
+    The Apache JAMES Parent POM
+  </description>
+
+  <prerequisites>
+    <maven>2.0.6</maven>
+  </prerequisites>
+  
+  <modules>
+    <module>maven-skin</module>
+    <module>project</module>
+  </modules>
+
+  <url>http://james.apache.org/</url>
+  <inceptionYear>2006</inceptionYear>
+  <packaging>pom</packaging>
+
+  <dependencies>
+  </dependencies>
+
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://www.apache.org</url>
+  </organization>
+
+  <licenses>
+    <license>
+      <name>Apache License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://issues.apache.org/jira/browse/JAMES</url>
+  </issueManagement>
+
+  <developers>
+    <developer>
+      <id>bago</id>
+      <name>Stefano Bagnara</name>
+      <email>bago at apache.org</email>
+      <timezone>2</timezone>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>norman</id>
+      <name>Norman Maurer</name>
+      <email>norman at apache.org</email>
+      <timezone>2</timezone>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>serge</id>
+      <name>Serge Knystautas</name>
+      <email>sergek at lokitech.com</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>benrdf</id>
+      <name>Bernd Fondermann</name>
+      <email>bf_jak at brainlounge.de</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>sbrewin</id>
+      <name>Steve Brewin</name>
+      <email>sbrewin at synsys.com</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>hilmer</id>
+      <!-- This is not correctly handled by maven release plugin -->
+      <!-- <name>S&#248;ren Hilmer</name> -->
+      <name>Soren Hilmer</name>
+      <email>sh at widetrail.dk</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>noel</id>
+      <name>Noel J. Bergman</name>
+      <email>noel at devtech.com</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>danny</id>
+      <name>Danny Angus</name>
+      <email>danny at apache.org</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>adc</id>
+      <name>Alan D. Cabrera</name>
+      <email>list at toolazydogs.com</email>
+      <timezone>-8</timezone>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>vincenzo</id>
+      <name>Vincenzo Gianferrari Pini</name>
+      <email>vincenzo.gianferraripini at praxis.it</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>rdonkin</id>
+      <name>Robert Burrell Donkin</name>
+      <email>rdonkin at apache.org</email>
+      <timezone />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>niklas</id>
+      <name>Niklas Therning</name>
+      <email>niklas(at)apache(dot)org</email>
+      <organization>Trillian AB</organization>
+    </developer>
+    <developer>
+      <id>jcheng</id>
+      <name>Joe Cheng</name>
+      <email>joe(at)joecheng(dot)com</email>
+      <properties>
+        <description>
+          Former author to the mime4j product
+        </description>
+      </properties>
+    </developer>
+  </developers>
+
+  <contributors>
+    <contributor>
+      <name>Rob Oxspring</name>
+      <properties>
+        <description>
+          Contributed to the mime4j product
+        </description>
+      </properties>
+    </contributor>
+    <contributor>
+      <name>Roger Fullerton</name>
+      <properties>
+        <description>
+          Wrote spfjava, the first spf implementation in java
+        </description>
+      </properties>
+    </contributor>
+  </contributors>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/james/project/tags/james-parent-1.1</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/james/project/tags/james-parent-1.1</developerConnection>
+    <url>http://svn.apache.org/viewvc/james/project/tags/james-parent-1.1</url>
+  </scm>
+
+  <distributionManagement>
+    <repository>
+      <id>apache.releases</id>
+      <name>Apache Release Distribution Repository</name>
+      <url>scp://people.apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+    </repository>
+    <snapshotRepository>
+      <id>apache.snapshots</id>
+      <name>Apache Development Snapshot Repository</name>
+      <url>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
+    </snapshotRepository>
+    <!-- Each project must override this with their own -->
+    <site>
+      <id>james-parent-website</id>
+      <url>scp://minotaur.apache.org/www/james.apache.org/parent/</url>
+    </site>
+  </distributionManagement>
+
+  <repositories>
+    <repository>
+      <id>central</id>
+      <url>http://repo1.maven.org/maven2</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+    <repository>
+      <id>apache.releases</id>
+      <name>Apache Main M2 Repository</name>
+      <url>http://people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+      <releases>
+        <enabled>true</enabled>
+      </releases>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+    <repository>
+      <id>apache.snapshots</id>
+      <name>Apache Snapshot Repository</name>
+      <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+  
+  <profiles>
+    <!-- parent profile: used to find skin dependency in stage -->
+    <profile>
+      <id>parent</id>
+      <repositories>
+        <repository>
+          <id>local-james-parent-stage</id>
+          <name>Apache JAMES parent stage repository folder</name>
+          <url>file://${basedir}/stage</url>
+          <layout>legacy</layout>
+          <releases>
+            <enabled>true</enabled>
+            <checksumPolicy>ignore</checksumPolicy>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+            <checksumPolicy>ignore</checksumPolicy>
+          </snapshots>
+        </repository>
+      </repositories>
+    </profile>
+    <!-- local profile: used to ignore remote repositories in a local build -->
+    <profile>
+      <id>local</id>
+      <repositories>
+        <repository>
+          <id>central</id>
+          <url>http://repo1.maven.org/maven2</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+        <repository>
+          <id>apache.releases</id>
+          <name>Apache Main M2 Repository</name>
+          <url>http://people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+        <repository>
+          <id>apache.snapshots</id>
+          <name>Apache Snapshot Repository</name>
+          <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+    </profile>
+    <!-- START SNIPPET: release-profile -->
+    <profile>
+      <id>release</id>
+      <build>
+        <plugins>
+          <!-- We want to sign the artifact, the POM, and all attached artifacts -->
+          <plugin>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.0-alpha-3</version>
+            <configuration>
+              <passphrase>${gpg.passphrase}</passphrase>
+            </configuration>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <!-- We want to deploy the artifact to a staging location for perusal -->
+          <plugin>
+            <inherited>true</inherited>
+            <artifactId>maven-deploy-plugin</artifactId>
+            <version>2.3</version>
+            <configuration>
+              <altDeploymentRepository>${deploy.altRepository}</altDeploymentRepository>
+              <updateReleaseInfo>true</updateReleaseInfo>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>2.0.2</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>2.2</version>
+            <executions>
+              <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <!-- END SNIPPET: release-profile -->
+  </profiles>  
+
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/org.apache.james/poms/james-project-1.2.pom b/apache-mime4j-0.6/stage/org.apache.james/poms/james-project-1.2.pom
new file mode 100644
index 0000000..4b2e41d
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/poms/james-project-1.2.pom
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+  
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.    
+  -->
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.james</groupId>
+  <artifactId>james-project</artifactId>
+  <name>Apache JAMES Project</name>
+  <version>1.2</version>
+  <description>
+    The Apache JAMES Project
+  </description>
+  
+  <parent>
+    <groupId>org.apache.james</groupId>
+    <artifactId>james-parent</artifactId>
+    <version>1.1</version>
+  </parent>
+
+  <modules>
+    <module>server</module>
+  </modules>
+  
+  <url>http://james.apache.org/</url>
+  <inceptionYear>2006</inceptionYear>
+  <packaging>pom</packaging>
+
+  <dependencies>
+  </dependencies>
+
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://issues.apache.org/jira/browse/JAMES</url>
+  </issueManagement>
+
+  <distributionManagement>
+    <!-- Each project must override this with their own -->
+    <site>
+      <id>james-website</id>
+      <url>scp://minotaur.apache.org/www/james.apache.org/</url>
+    </site>
+  </distributionManagement>
+
+  <mailingLists>
+    <mailingList>
+      <name>Apache James Website Developement</name>
+      <subscribe>site-dev-subscribe@james.apache.org</subscribe>
+      <unsubscribe>site-dev-unsubscribe@james.apache.org</unsubscribe>
+      <post>site-dev@james.apache.org</post>
+      <archive>http://mail-archives.apache.org/mod_mbox/james-site-dev/</archive>
+    </mailingList>
+  </mailingLists>
+  
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/james/project/tags/james-project-1.2</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/james/project/tags/james-project-1.2</developerConnection>
+    <url>http://svn.apache.org/viewvc/james/project/tags/james-project-1.2</url>
+  </scm>
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/org.apache.james/poms/maven-skin-1.1.pom b/apache-mime4j-0.6/stage/org.apache.james/poms/maven-skin-1.1.pom
new file mode 100644
index 0000000..d8f19e0
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/poms/maven-skin-1.1.pom
@@ -0,0 +1,66 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.    
+-->
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.james</groupId>
+  <artifactId>maven-skin</artifactId>
+  <version>1.1</version>
+  <name>JAMES Skin</name>
+  <description>Apache JAMES Official Maven2 Site Skin</description>
+
+  <parent>
+    <groupId>org.apache.james</groupId>
+    <artifactId>james-parent</artifactId>
+    <version>1.1</version>
+  </parent>
+
+
+  <distributionManagement>
+    <site>
+      <id>maven-skin-website</id>
+      <url>scp://minotaur.apache.org/www/james.apache.org/maven-skin</url>
+    </site>
+  </distributionManagement>
+
+  <!-- This is here because of http://jira.codehaus.org/browse/MRRESOURCES-6 -->
+  <properties>
+    <maven.test.skip>true</maven.test.skip>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <resourceBundles>
+                <resourceBundle>org.apache:apache-jar-resource-bundle:1.2</resourceBundle>
+              </resourceBundles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/org.apache.james/xmls/james-parent-1.1-site.xml b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-parent-1.1-site.xml
new file mode 100644
index 0000000..95601af
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-parent-1.1-site.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?><project name="James Parent POM">
+  <bannerLeft>
+    <name>James Project</name>
+    <src>images/james-project-logo.gif</src>
+    <href>http://james.apache.org/index.html</href>
+  </bannerLeft>
+  <bannerRight>
+    <name>The Apache Software Foundation</name>
+    <src>images/asf-logo-reduced.gif</src>
+    <href>http://www.apache.org/index.html</href>
+  </bannerRight>
+  <skin>
+    <groupId>org.apache.maven.skins</groupId>
+    <artifactId>maven-default-skin</artifactId>
+    <version>1.0</version>
+  </skin>
+  <body />
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/org.apache.james/xmls/james-parent-1.1-site_en.xml b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-parent-1.1-site_en.xml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-parent-1.1-site_en.xml
diff --git a/apache-mime4j-0.6/stage/org.apache.james/xmls/james-project-1.2-site.xml b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-project-1.2-site.xml
new file mode 100644
index 0000000..2d94949
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-project-1.2-site.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="ISO-8859-1"?><project name="James Project">
+  <bannerLeft>
+    <name>James Project</name>
+    <src>images/james-project-logo.gif</src>
+    <href>http://james.apache.org/index.html</href>
+  </bannerLeft>
+  <bannerRight>
+    <name>The Apache Software Foundation</name>
+    <src>images/asf-logo-reduced.gif</src>
+    <href>http://www.apache.org/index.html</href>
+  </bannerRight>
+  <skin>
+    <groupId>org.apache.james</groupId>
+    <artifactId>maven-skin</artifactId>
+    <version>1.1</version>
+  </skin>
+  <body>
+    <links>
+      <item name="JAMES Project" href="/index.html" />
+      <item name="Server" href="/server/index.html" />
+      <item name="Mailet API" href="/mailet/index.html" />
+      <item name="jSPF" href="/jspf/index.html" />
+      <item name="Mime4J" href="/mime4j/index.html" />
+      <item name="JSieve" href="/jsieve/index.html" />
+      <item name="Postage" href="/postage/index.html" />
+    </links>
+    <menu name="Sub Projects">
+      <item name="Server" href="/server/index.html" />
+      <item name="Mailet API" href="/mailet/index.html" />
+      <item name="jSPF" href="/jspf/index.html" />
+      <item name="Mime4J" href="/mime4j/index.html" />
+      <item name="JSieve" href="/jsieve/index.html" />
+      <item name="Postage" href="/postage/index.html" />
+    </menu>
+    <menu name="About">
+      <item name="News" href="/newsarchive.html" />
+      <item name="Overview" href="/index.html" />
+      <item name="Mailing Lists" href="/mail.html" />
+      <item name="Project Guidelines" href="/guidelines.html" />
+      <item name="Wiki" href="http://wiki.apache.org/james" />
+      <item name="Who We Are" href="/weare.html" />
+      <item name="Contributing" href="/contribute.html" />
+      <item name="Standards" href="/code-standards.html" />
+      <item name="License" href="/license.html" />
+    </menu>
+    <menu name="Downloads" inherit="bottom">
+      <item name="Stable releases" href="/download.cgi" />
+      <item name="Unstable releases" href="/downloadunstable.cgi" />
+      <item name="Nightly builds" href="http://people.apache.org/builds/james/nightly/" />
+    </menu>
+    <menu name="Translated">
+      <item name="Japanese (web)" href="http://james.terra-intl.com/" />
+    </menu>
+    <menu name="Related Projects">
+      <item name="Jakarta Commons" href="http://jakarta.apache.org/commons/index.html" />
+      <item name="Ant" href="http://ant.apache.org/index.html" />
+      <item name="Maven2" href="http://maven.apache.org/index.html" />
+      <item name="Derby" href="http://db.apache.org/derby/index.html" />
+      <item name="Avalon" href="http://avalon.apache.org/index.html" />
+      <item name="DNSJava" href="http://www.dnsjava.org/index.html" />
+    </menu>
+    <menu name="Useful Information">
+      <item name="Get Involved" href="http://jakarta.apache.org/site/getinvolved.html" />
+      <item name="Reference Library" href="http://jakarta.apache.org/site/library.html" />
+      <item name="Apache" href="http://apache.org/foundation/faq.html" />
+    </menu>
+  </body>
+</project>
\ No newline at end of file
diff --git a/apache-mime4j-0.6/stage/org.apache.james/xmls/james-project-1.2-site_en.xml b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-project-1.2-site_en.xml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache.james/xmls/james-project-1.2-site_en.xml
diff --git a/apache-mime4j-0.6/stage/org.apache/jars/apache-jar-resource-bundle-1.2.jar b/apache-mime4j-0.6/stage/org.apache/jars/apache-jar-resource-bundle-1.2.jar
new file mode 100644
index 0000000..2d2c1b4
--- /dev/null
+++ b/apache-mime4j-0.6/stage/org.apache/jars/apache-jar-resource-bundle-1.2.jar
Binary files differ