You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mime4j-dev@james.apache.org by mw...@apache.org on 2009/02/01 20:38:00 UTC
svn commit: r739822 - in /james/mime4j/trunk:
examples/src/java/org/apache/james/mime4j/samples/dom/
examples/src/java/org/apache/james/mime4j/samples/transform/
src/main/java/org/apache/james/mime4j/message/
src/test/java/org/apache/james/mime4j/message/
Author: mwiederkehr
Date: Sun Feb 1 19:37:59 2009
New Revision: 739822
URL: http://svn.apache.org/viewvc?rev=739822&view=rev
Log:
MIME4J-110: added a dedicated MessageWriter class
Added:
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/MessageWriter.java
Removed:
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Mode.java
Modified:
james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java
james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java
james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Body.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Header.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Message.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
Modified: james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java (original)
+++ james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/MultipartMessage.java Sun Feb 1 19:37:59 2009
@@ -34,7 +34,6 @@
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.Mode;
import org.apache.james.mime4j.message.Multipart;
import org.apache.james.mime4j.message.TextBody;
import org.apache.james.mime4j.storage.Storage;
@@ -88,7 +87,7 @@
// 4) print message to standard output
- message.writeTo(System.out, Mode.STRICT_ERROR);
+ message.writeTo(System.out);
// 5) message is no longer needed and should be disposed of
Modified: james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java (original)
+++ james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/dom/TextPlainMessage.java Sun Feb 1 19:37:59 2009
@@ -25,7 +25,6 @@
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.Mode;
import org.apache.james.mime4j.message.TextBody;
/**
@@ -62,7 +61,7 @@
// 4) print message to standard output
- message.writeTo(System.out, Mode.STRICT_ERROR);
+ message.writeTo(System.out);
// 5) message is no longer needed and should be disposed of
Modified: james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java (original)
+++ james/mime4j/trunk/examples/src/java/org/apache/james/mime4j/samples/transform/TransformMessage.java Sun Feb 1 19:37:59 2009
@@ -29,7 +29,6 @@
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.Mode;
import org.apache.james.mime4j.message.Multipart;
import org.apache.james.mime4j.message.TextBody;
import org.apache.james.mime4j.storage.DefaultStorageProvider;
@@ -61,7 +60,7 @@
// Print transformed message.
System.out.println("\n\nTransformed message:\n--------------------\n");
- transformed.writeTo(System.out, Mode.STRICT_ERROR);
+ 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
@@ -71,7 +70,7 @@
// 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, Mode.STRICT_ERROR);
+ template.writeTo(System.out);
// Original message is no longer needed.
template.dispose();
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Body.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Body.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Body.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Body.java Sun Feb 1 19:37:59 2009
@@ -19,16 +19,12 @@
package org.apache.james.mime4j.message;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.james.mime4j.MimeIOException;
-
/**
* Encapsulates the body of an entity (see RFC 2045).
- *
- *
- * @version $Id: Body.java,v 1.4 2004/10/04 15:36:43 ntherning Exp $
+ * <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 {
@@ -38,21 +34,13 @@
* @return the parent.
*/
Entity getParent();
-
+
/**
* Sets the parent of this body.
*
- * @param parent the parent.
+ * @param parent
+ * the parent.
*/
void setParent(Entity parent);
-
- /**
- * Writes this body to the given stream in MIME message format.
- *
- * @param out the stream to write to.
- * @param mode compatibility mode
- * @throws IOException if case of an I/O error
- * @throws MimeIOException if case of a MIME protocol violation
- */
- void writeTo(OutputStream out, Mode mode) throws IOException, MimeIOException;
+
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java Sun Feb 1 19:37:59 2009
@@ -244,8 +244,8 @@
* <p>
* "us-ascii" is used to encode the characters of the string into
* a byte stream when calling
- * {@link Body#writeTo(java.io.OutputStream, Mode) writeTo(OutputStream, Mode)}
- * on the returned object.
+ * {@link SingleBody#writeTo(java.io.OutputStream) writeTo(OutputStream)} on
+ * the returned object.
*
* @param text
* text to create a message body from.
@@ -264,8 +264,8 @@
* <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 Body#writeTo(java.io.OutputStream, Mode) writeTo(OutputStream, Mode)}
- * on the returned object. If the MIME charset has no corresponding Java
+ * {@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
* "us-ascii" is used instead.
*
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Entity.java Sun Feb 1 19:37:59 2009
@@ -19,15 +19,11 @@
package org.apache.james.mime4j.message;
-import java.io.IOException;
-import java.io.OutputStream;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-import org.apache.james.mime4j.MimeIOException;
-import org.apache.james.mime4j.codec.CodecUtil;
import org.apache.james.mime4j.field.ContentDispositionField;
import org.apache.james.mime4j.field.ContentTransferEncodingField;
import org.apache.james.mime4j.field.ContentTypeField;
@@ -37,9 +33,6 @@
/**
* MIME entity. An entity has a header and a body (see RFC 2045).
- *
- *
- * @version $Id: Entity.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
*/
public abstract class Entity implements Disposable {
private Header header = null;
@@ -489,37 +482,6 @@
return f != null && f.getBoundary() != null
&& getMimeType().startsWith(ContentTypeField.TYPE_MULTIPART_PREFIX);
}
-
- /**
- * Write the content to the given outputstream
- *
- * @param out the outputstream to write to
- * @param mode compatibility mode
- * @throws IOException if case of an I/O error
- * @throws MimeIOException if case of a MIME protocol violation
- */
- public void writeTo(OutputStream out, Mode mode) throws IOException, MimeIOException {
- getHeader().writeTo(out, mode);
-
- out.flush();
-
- final Body body = getBody();
-
- OutputStream encOut;
- if (MimeUtil.ENC_BASE64.equals(getContentTransferEncoding())) {
- encOut = CodecUtil.wrapBase64(out);
- } else if (MimeUtil.ENC_QUOTED_PRINTABLE.equals(getContentTransferEncoding())) {
- encOut = CodecUtil.wrapQuotedPrintable(out, (body instanceof BinaryBody));
- } else {
- encOut = out;
- }
- body.writeTo(encOut, mode);
- encOut.flush();
- // the Base64 output streams requires closing of the stream but
- // we don't want it to close the inner stream so we override the behaviour
- // for the wrapping stream writer.
- if (encOut != out) encOut.close();
- }
/**
* Disposes of the body of this entity. Note that the dispose call does not
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Header.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Header.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Header.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Header.java Sun Feb 1 19:37:59 2009
@@ -19,12 +19,8 @@
package org.apache.james.mime4j.message;
-import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -34,20 +30,15 @@
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.MimeIOException;
-import org.apache.james.mime4j.field.ContentTypeField;
import org.apache.james.mime4j.field.Field;
import org.apache.james.mime4j.parser.AbstractContentHandler;
import org.apache.james.mime4j.parser.MimeStreamParser;
-import org.apache.james.mime4j.util.CharsetUtil;
-
/**
* The header of an entity (see RFC 2045).
- *
- *
- * @version $Id: Header.java,v 1.3 2004/10/04 15:36:44 ntherning Exp $
*/
public class Header implements Iterable<Field> {
+
private List<Field> fields = new LinkedList<Field>();
private Map<String, List<Field>> fieldMap = new HashMap<String, List<Field>>();
@@ -243,46 +234,5 @@
}
return str.toString();
}
-
-
- /**
- * Write the Header to the given OutputStream using the specified
- * compatibility mode.
- *
- * @param out the OutputStream to write to
- * @param mode compatibility mode
- *
- * @throws IOException if case of an I/O error
- * @throws MimeIOException if case of a MIME protocol violation
- */
- public void writeTo(final OutputStream out, Mode mode) throws IOException, MimeIOException {
- Charset charset = null;
- if (mode == Mode.LENIENT) {
- final ContentTypeField contentTypeField = ((ContentTypeField) getField(Field.CONTENT_TYPE));
- if (contentTypeField == null) {
- charset = CharsetUtil.DEFAULT_CHARSET;
- } else {
- final String contentTypeFieldCharset = contentTypeField.getCharset();
- if (contentTypeField != null && contentTypeFieldCharset != null) {
- charset = CharsetUtil.getCharset(contentTypeFieldCharset);
- } else {
- charset = CharsetUtil.ISO_8859_1;
- }
- }
- } else {
- charset = CharsetUtil.DEFAULT_CHARSET;
- }
- BufferedWriter writer = new BufferedWriter(
- new OutputStreamWriter(out, charset), 8192);
- for (Field field : fields) {
- String fs = field.getRaw();
- if (mode == Mode.STRICT_ERROR && !CharsetUtil.isASCII(fs)) {
- throw new MimeIOException(new MimeException("Header '" + fs + "' violates RFC 822"));
- }
- writer.write(fs);
- writer.write(CharsetUtil.CRLF);
- }
- writer.write(CharsetUtil.CRLF);
- writer.flush();
- }
+
}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Message.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Message.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Message.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Message.java Sun Feb 1 19:37:59 2009
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -133,7 +134,23 @@
throw new MimeIOException(e);
}
}
-
+
+ /**
+ * Write the content to the given output stream using the
+ * {@link MessageWriter#STRICT_ERROR STRICT_ERROR} message writer.
+ *
+ * @param out
+ * the output stream to write to.
+ * @throws IOException
+ * in case of an I/O error
+ * @throws MimeIOException
+ * in case of a MIME protocol violation
+ * @see MessageWriter
+ */
+ public void writeTo(OutputStream out) throws IOException, MimeIOException {
+ MessageWriter.STRICT_ERROR.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.
Added: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/MessageWriter.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/MessageWriter.java?rev=739822&view=auto
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/MessageWriter.java (added)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/MessageWriter.java Sun Feb 1 19:37:59 2009
@@ -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.message;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+
+import org.apache.james.mime4j.MimeIOException;
+import org.apache.james.mime4j.codec.CodecUtil;
+import org.apache.james.mime4j.field.ContentTypeField;
+import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.util.CharsetUtil;
+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 three static instances
+ * {@link #STRICT_ERROR}, {@link #STRICT_IGNORE} or {@link #LENIENT} implement
+ * different strategies for encoding header fields and preamble and epilogue of
+ * a multipart.
+ * <p>
+ * This class can also be subclassed to implement custom strategies for writing
+ * messages.
+ */
+public class MessageWriter {
+
+ private static final Charset LENIENT_FALLBACK_CHARSET = CharsetUtil.ISO_8859_1;
+ private static final String CRLF = CharsetUtil.CRLF;
+ private static final int WRITER_BUFFER_SIZE = 4096;
+
+ /**
+ * A message writer that uses US-ASCII for encoding and throws
+ * {@link MimeIOException} if a non ASCII character is encountered.
+ */
+ public static final MessageWriter STRICT_ERROR = new MessageWriter();
+
+ /**
+ * A message writer that uses US-ASCII for encoding but ignores non ASCII
+ * characters.
+ */
+ public static final MessageWriter STRICT_IGNORE = new MessageWriter() {
+ @Override
+ protected CharsetEncoder getCharsetEncoder(ContentTypeField contentType) {
+ return ignoreEncoder(CharsetUtil.DEFAULT_CHARSET);
+ }
+ };
+
+ /**
+ * A message writer that uses the charset of the Content-Type header for
+ * encoding.
+ */
+ public static final MessageWriter LENIENT = new MessageWriter() {
+ @Override
+ protected CharsetEncoder getCharsetEncoder(ContentTypeField contentType) {
+ if (contentType == null) {
+ return ignoreEncoder(LENIENT_FALLBACK_CHARSET);
+ } else {
+ String charset = contentType.getCharset();
+ if (charset != null) {
+ return ignoreEncoder(CharsetUtil.getCharset(charset));
+ } else {
+ return ignoreEncoder(LENIENT_FALLBACK_CHARSET);
+ }
+ }
+ }
+ };
+
+ /**
+ * 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.
+ * @throws MimeIOException
+ * in case of a MIME protocol violation
+ */
+ public void writeBody(Body body, OutputStream out) throws IOException,
+ MimeIOException {
+ 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");
+
+ out.flush();
+ }
+
+ /**
+ * 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.
+ * @throws MimeIOException
+ * in case of a MIME protocol violation
+ */
+ public void writeEntity(Entity entity, OutputStream out)
+ throws IOException, MimeIOException {
+ final Header header = entity.getHeader();
+ if (header == null)
+ throw new IllegalArgumentException("Missing header");
+
+ writeHeader(header, out);
+ out.flush();
+
+ 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.
+ * @throws MimeIOException
+ * in case of a MIME protocol violation
+ */
+ public void writeMultipart(Multipart multipart, OutputStream out)
+ throws IOException, MimeIOException {
+ ContentTypeField contentType = getContentType(multipart);
+
+ String boundary = getBoundary(contentType);
+
+ Writer writer = getWriter(contentType, out);
+
+ try {
+ writer.write(multipart.getPreamble());
+ writer.write(CRLF);
+
+ for (BodyPart bodyPart : multipart.getBodyParts()) {
+ writer.write("--");
+ writer.write(boundary);
+ writer.write(CRLF);
+ writer.flush();
+
+ writeEntity(bodyPart, out);
+ writer.write(CRLF);
+ }
+
+ writer.write("--");
+ writer.write(boundary);
+ writer.write("--");
+ writer.write(CRLF);
+
+ writer.write(multipart.getEpilogue());
+
+ writer.flush();
+ } catch (CharacterCodingException e) {
+ throw new MimeIOException("Multipart violates RFC 822");
+ }
+ }
+
+ /**
+ * 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.
+ * @throws MimeIOException
+ * in case of a MIME protocol violation
+ */
+ public void writeHeader(Header header, OutputStream out)
+ throws IOException, MimeIOException {
+ Writer writer = getWriter((ContentTypeField) header
+ .getField(Field.CONTENT_TYPE), out);
+
+ try {
+ for (Field field : header) {
+ writer.write(field.getRaw());
+ writer.write(CRLF);
+ }
+
+ writer.write(CRLF);
+ writer.flush();
+ } catch (CharacterCodingException e) {
+ throw new MimeIOException("Header violates RFC 822");
+ }
+ }
+
+ CharsetEncoder getCharsetEncoder(ContentTypeField contentType) {
+ return CharsetUtil.DEFAULT_CHARSET.newEncoder();
+ }
+
+ CharsetEncoder ignoreEncoder(Charset charset) {
+ return charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+
+ private 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(Field.CONTENT_TYPE);
+ if (contentType == null)
+ throw new IllegalArgumentException(
+ "Content-Type field not specified");
+
+ return contentType;
+ }
+
+ private String getBoundary(ContentTypeField contentType) {
+ String boundary = contentType.getBoundary();
+ if (boundary == null)
+ throw new IllegalArgumentException(
+ "Multipart boundary not specified");
+
+ return boundary;
+ }
+
+ private Writer getWriter(ContentTypeField contentType, OutputStream out) {
+ CharsetEncoder encoder = getCharsetEncoder(contentType);
+
+ return new BufferedWriter(new OutputStreamWriter(out, encoder),
+ WRITER_BUFFER_SIZE);
+ }
+
+}
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/Multipart.java Sun Feb 1 19:37:59 2009
@@ -19,30 +19,16 @@
package org.apache.james.mime4j.message;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.Charset;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
-import org.apache.james.mime4j.MimeException;
-import org.apache.james.mime4j.MimeIOException;
-import org.apache.james.mime4j.field.ContentTypeField;
-import org.apache.james.mime4j.field.Field;
-import org.apache.james.mime4j.util.CharsetUtil;
-
/**
* 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.
- *
- *
- * @version $Id: Multipart.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
*/
public class Multipart implements Body {
private String preamble = "";
@@ -270,63 +256,6 @@
}
/**
- * Write the Multipart to the given OutputStream.
- *
- * @param out the OutputStream to write to
- * @param mode compatibility mode
- *
- * @throws IOException if case of an I/O error
- * @throws MimeIOException if case of a MIME protocol violation
- */
- public void writeTo(final OutputStream out, Mode mode) throws IOException, MimeIOException {
- Entity e = getParent();
-
- ContentTypeField cField = (ContentTypeField) e.getHeader().getField(
- Field.CONTENT_TYPE);
- if (cField == null || cField.getBoundary() == null) {
- throw new MimeIOException(new MimeException("Multipart boundary not specified"));
- }
- String boundary = cField.getBoundary();
-
- Charset charset = null;
- if (mode == Mode.LENIENT) {
- if (cField != null && cField.getCharset() != null) {
- charset = CharsetUtil.getCharset(cField.getCharset());
- } else {
- charset = CharsetUtil.ISO_8859_1;
- }
- } else {
- charset = CharsetUtil.DEFAULT_CHARSET;
- }
-
- BufferedWriter writer = new BufferedWriter(
- new OutputStreamWriter(out, charset), 8192);
-
- List<BodyPart> bodyParts = getBodyParts();
-
- writer.write(getPreamble());
- writer.write(CharsetUtil.CRLF);
-
- for (int i = 0; i < bodyParts.size(); i++) {
- writer.write("--");
- writer.write(boundary);
- writer.write(CharsetUtil.CRLF);
- writer.flush();
- final BodyPart bodyPart = bodyParts.get(i);
- bodyPart.writeTo(out, mode);
- writer.write(CharsetUtil.CRLF);
- }
-
- writer.write("--");
- writer.write(boundary);
- writer.write("--");
- writer.write(CharsetUtil.CRLF);
- final String epilogue = getEpilogue();
- writer.write(epilogue);
- writer.flush();
- }
-
- /**
* Disposes of the BodyParts of this Multipart. Note that the dispose call
* does not get forwarded to the parent entity of this Multipart.
*
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java Sun Feb 1 19:37:59 2009
@@ -19,6 +19,9 @@
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
@@ -43,6 +46,14 @@
}
/**
+ * 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:
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java Sun Feb 1 19:37:59 2009
@@ -45,11 +45,8 @@
return storage.getInputStream();
}
- /**
- * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream,
- * Mode)
- */
- public void writeTo(OutputStream out, Mode mode) throws IOException {
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
if (out == null)
throw new IllegalArgumentException();
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java Sun Feb 1 19:37:59 2009
@@ -57,11 +57,8 @@
return new InputStreamReader(storage.getInputStream(), charset);
}
- /**
- * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream,
- * Mode)
- */
- public void writeTo(OutputStream out, Mode mode) throws IOException {
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
if (out == null)
throw new IllegalArgumentException();
Modified: james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java (original)
+++ james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java Sun Feb 1 19:37:59 2009
@@ -56,11 +56,8 @@
return new StringReader(text);
}
- /**
- * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream,
- * Mode)
- */
- public void writeTo(OutputStream out, Mode mode) throws IOException {
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
if (out == null)
throw new IllegalArgumentException();
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/ExampleMessagesRoundtripTest.java Sun Feb 1 19:37:59 2009
@@ -64,7 +64,7 @@
config.setMaxLineLen(-1);
Message inputMessage = new Message(new FileInputStream(file), config);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- inputMessage.writeTo(out, Mode.LENIENT);
+ MessageWriter.LENIENT.writeEntity(inputMessage, out);
String msgoutFile = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + ".out";
String msgoutFileMime4j = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf('.')) + ".mime4j.out";
@@ -76,12 +76,12 @@
Message roundtripMessage = new Message(new FileInputStream(msgoutFile), config);
ByteArrayOutputStream outRoundtrip = new ByteArrayOutputStream();
- roundtripMessage.writeTo(outRoundtrip, Mode.LENIENT);
+ MessageWriter.LENIENT.writeEntity(roundtripMessage, outRoundtrip);
assertEquals("Failed LENIENT roundtrip", new String(out.toByteArray()), new String(outRoundtrip.toByteArray()));
roundtripMessage = new Message(new FileInputStream(msgoutFile), config);
outRoundtrip = new ByteArrayOutputStream();
- roundtripMessage.writeTo(outRoundtrip, Mode.STRICT_ERROR);
+ MessageWriter.STRICT_ERROR.writeEntity(roundtripMessage, outRoundtrip);
assertEquals("Failed STRICT roundtrip", new String(out.toByteArray()), new String(outRoundtrip.toByteArray()));
} catch (FileNotFoundException e) {
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/HeaderTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/HeaderTest.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/HeaderTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/HeaderTest.java Sun Feb 1 19:37:59 2009
@@ -44,22 +44,10 @@
.toString());
}
- static final int SWISS_GERMAN_HELLO [] = {
- 0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
- };
-
- private static String constructString(int [] unicodeChars) {
- StringBuilder buffer = new StringBuilder();
- if (unicodeChars != null) {
- for (int unicodeChar : unicodeChars) {
- buffer.append((char) unicodeChar);
- }
- }
- return buffer.toString();
- }
+ private static final String SWISS_GERMAN_HELLO = "Gr\374ezi_z\344m\344";
public void testWriteInStrictMode() throws Exception {
- String hello = constructString(SWISS_GERMAN_HELLO);
+ String hello = SWISS_GERMAN_HELLO;
Header header = new Header();
header.addField(Field.parse("Hello: " + hello));
@@ -69,7 +57,7 @@
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- header.writeTo(buffer, Mode.STRICT_IGNORE);
+ MessageWriter.STRICT_IGNORE.writeHeader(header, buffer);
String s = buffer.toString(CharsetUtil.US_ASCII.name());
assertEquals("Hello: Gr?ezi_z?m?\r\n\r\n", s);
@@ -77,14 +65,14 @@
buffer.reset();
try {
- header.writeTo(buffer, Mode.STRICT_ERROR);
+ MessageWriter.STRICT_ERROR.writeHeader(header, buffer);
fail("MimeIOException should have been thrown");
} catch (MimeIOException expected) {
}
}
public void testWriteInLenientMode() throws Exception {
- String hello = constructString(SWISS_GERMAN_HELLO);
+ String hello = SWISS_GERMAN_HELLO;
Header header = new Header();
header.addField(Field.parse("Hello: " + hello));
header.addField(Field.parse("Content-type: text/plain; charset=" +
@@ -96,7 +84,7 @@
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- header.writeTo(buffer, Mode.LENIENT);
+ MessageWriter.LENIENT.writeHeader(header, buffer);
String s = buffer.toString(CharsetUtil.ISO_8859_1.name());
assertEquals("Hello: " + hello + "\r\n" +
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java Sun Feb 1 19:37:59 2009
@@ -133,7 +133,7 @@
Message m = new Message(new ByteArrayInputStream(inputByte));
ByteArrayOutputStream out = new ByteArrayOutputStream();
- m.writeTo(out, Mode.LENIENT);
+ m.writeTo(out);
InputStream output = new ByteArrayInputStream(out.toByteArray());
@@ -159,7 +159,7 @@
.getBody(), headerValue);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- m.writeTo(out, Mode.LENIENT);
+ m.writeTo(out);
List<?> lines = IOUtils.readLines((new BufferedReader(
new InputStreamReader(new ByteArrayInputStream(out
.toByteArray())))));
@@ -495,7 +495,8 @@
public boolean disposed = false;
- public void writeTo(OutputStream out, Mode mode) throws IOException {
+ @Override
+ public void writeTo(OutputStream out) throws IOException {
out.write("dummy".getBytes("US-ASCII"));
}
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageWriteToTest.java Sun Feb 1 19:37:59 2009
@@ -42,7 +42,7 @@
Message message = createMessage(ExampleMail.RFC822_SIMPLE_BYTES);
assertFalse("Not multipart", message.isMultipart());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- message.writeTo(out, Mode.STRICT_IGNORE);
+ MessageWriter.STRICT_IGNORE.writeEntity(message, out);
assertEquals(out.toByteArray(), ExampleMail.RFC822_SIMPLE_BYTES);
}
@@ -50,7 +50,7 @@
Message message = createMessage(ExampleMail.RFC822_SIMPLE_BYTES);
assertFalse("Not multipart", message.isMultipart());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- message.writeTo(out, Mode.STRICT_ERROR);
+ MessageWriter.STRICT_ERROR.writeEntity(message, out);
assertEquals(out.toByteArray(), ExampleMail.RFC822_SIMPLE_BYTES);
}
@@ -58,7 +58,7 @@
Message message = createMessage(ExampleMail.RFC822_SIMPLE_BYTES);
assertFalse("Not multipart", message.isMultipart());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- message.writeTo(out, Mode.LENIENT);
+ MessageWriter.LENIENT.writeEntity(message, out);
assertEquals(out.toByteArray(), ExampleMail.RFC822_SIMPLE_BYTES);
}
@@ -75,7 +75,7 @@
Message message = createMessage(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES);
assertTrue("Is multipart", message.isMultipart());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- message.writeTo(out, Mode.LENIENT);
+ MessageWriter.LENIENT.writeEntity(message, out);
assertEquals(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES, out.toByteArray());
}
@@ -83,7 +83,7 @@
Message message = createMessage(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES);
assertTrue("Is multipart", message.isMultipart());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- message.writeTo(out, Mode.STRICT_ERROR);
+ MessageWriter.STRICT_ERROR.writeEntity(message, out);
assertEquals(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES, out.toByteArray());
}
@@ -91,7 +91,7 @@
Message message = createMessage(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES);
assertTrue("Is multipart", message.isMultipart());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- message.writeTo(out, Mode.STRICT_IGNORE);
+ MessageWriter.STRICT_IGNORE.writeEntity(message, out);
assertEquals(ExampleMail.MULTIPART_WITH_BINARY_ATTACHMENTS_BYTES, out.toByteArray());
}
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MultipartFormTest.java Sun Feb 1 19:37:59 2009
@@ -21,16 +21,10 @@
import java.io.ByteArrayOutputStream;
-import org.apache.james.mime4j.field.Field;
-
import junit.framework.TestCase;
-/**
- *
- *
- *
- * @version $Id:$
- */
+import org.apache.james.mime4j.field.Field;
+
public class MultipartFormTest extends TestCase {
public void testMultipartFormContent() throws Exception {
@@ -65,7 +59,7 @@
multipart.addBodyPart(p3);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- multipart.writeTo(out, Mode.LENIENT);
+ MessageWriter.LENIENT.writeMultipart(multipart, out);
out.close();
String expected = "\r\n" +
Modified: james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java?rev=739822&r1=739821&r2=739822&view=diff
==============================================================================
--- james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java (original)
+++ james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java Sun Feb 1 19:37:59 2009
@@ -91,11 +91,11 @@
private void sameContentTest(SingleBody expectedBody, SingleBody actualBody)
throws Exception {
ByteArrayOutputStream expBaos = new ByteArrayOutputStream();
- expectedBody.writeTo(expBaos, Mode.STRICT_ERROR);
+ expectedBody.writeTo(expBaos);
byte[] expected = expBaos.toByteArray();
ByteArrayOutputStream actBaos = new ByteArrayOutputStream();
- actualBody.writeTo(actBaos, Mode.STRICT_ERROR);
+ actualBody.writeTo(actBaos);
byte[] actual = actBaos.toByteArray();
assertEquals(expected.length, actual.length);