source: contrib/MailArchiver/sources/vendor/mime4j/custom/dom/src/main/java/org/apache/james/mime4j/message/MimeWriter.java @ 6785

Revision 6785, 9.7 KB checked in by rafaelraymundo, 12 years ago (diff)

Ticket #2946 - Liberado codigo do MailArchiver?. Documentação na subpasta DOCS.

Line 
1/****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one   *
3 * or more contributor license agreements.  See the NOTICE file *
4 * distributed with this work for additional information        *
5 * regarding copyright ownership.  The ASF licenses this file   *
6 * to you under the Apache License, Version 2.0 (the            *
7 * "License"); you may not use this file except in compliance   *
8 * with the License.  You may obtain a copy of the License at   *
9 *                                                              *
10 *   http://www.apache.org/licenses/LICENSE-2.0                 *
11 *                                                              *
12 * Unless required by applicable law or agreed to in writing,   *
13 * software distributed under the License is distributed on an  *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15 * KIND, either express or implied.  See the License for the    *
16 * specific language governing permissions and limitations      *
17 * under the License.                                           *
18 ****************************************************************/
19
20package org.apache.james.mime4j.message;
21
22import java.io.IOException;
23import java.io.OutputStream;
24
25import org.apache.james.mime4j.codec.CodecUtil;
26import org.apache.james.mime4j.dom.BinaryBody;
27import org.apache.james.mime4j.dom.Body;
28import org.apache.james.mime4j.dom.Entity;
29import org.apache.james.mime4j.dom.Header;
30import org.apache.james.mime4j.dom.Message;
31import org.apache.james.mime4j.dom.Multipart;
32import org.apache.james.mime4j.dom.SingleBody;
33import org.apache.james.mime4j.dom.field.ContentTypeField;
34import org.apache.james.mime4j.dom.field.Field;
35import org.apache.james.mime4j.dom.field.FieldName;
36import org.apache.james.mime4j.dom.field.FieldRawData;
37import org.apache.james.mime4j.util.ByteArrayBuffer;
38import org.apache.james.mime4j.util.ByteSequence;
39import org.apache.james.mime4j.util.ContentUtil;
40import org.apache.james.mime4j.util.MimeUtil;
41
42/**
43 * Writes a message (or a part of a message) to an output stream.
44 * <p>
45 * This class cannot be instantiated; instead the static instance
46 * {@link #DEFAULT} implements the default strategy for writing a message.
47 * <p>
48 * This class may be subclassed to implement custom strategies for writing
49 * messages.
50 */
51public class MimeWriter {
52
53    private static final byte[] CRLF = { '\r', '\n' };
54    private static final byte[] DASHES = { '-', '-' };
55
56    /**
57     * The default message writer.
58     */
59    public static final MimeWriter DEFAULT = new MimeWriter();
60
61    /**
62     * Protected constructor prevents direct instantiation.
63     */
64    protected MimeWriter() {
65    }
66
67    /**
68     * Write the specified <code>Body</code> to the specified
69     * <code>OutputStream</code>.
70     *
71     * @param body
72     *            the <code>Body</code> to write.
73     * @param out
74     *            the OutputStream to write to.
75     * @throws IOException
76     *             if an I/O error occurs.
77     */
78    public void writeBody(Body body, OutputStream out) throws IOException {
79        if (body instanceof Message) {
80            writeEntity((Message) body, out);
81        } else if (body instanceof Multipart) {
82            writeMultipart((Multipart) body, out);
83        } else if (body instanceof SingleBody) {
84            ((SingleBody) body).writeTo(out);
85        } else
86            throw new IllegalArgumentException("Unsupported body class");
87    }
88
89    /**
90     * Write the specified <code>Entity</code> to the specified
91     * <code>OutputStream</code>.
92     *
93     * @param entity
94     *            the <code>Entity</code> to write.
95     * @param out
96     *            the OutputStream to write to.
97     * @throws IOException
98     *             if an I/O error occurs.
99     */
100    public void writeEntity(Entity entity, OutputStream out) throws IOException {
101        final Header header = entity.getHeader();
102        if (header == null)
103            throw new IllegalArgumentException("Missing header");
104
105        writeHeader(header, out);
106
107        final Body body = entity.getBody();
108        if (body == null)
109            throw new IllegalArgumentException("Missing body");
110
111        boolean binaryBody = body instanceof BinaryBody;
112        OutputStream encOut = encodeStream(out, entity
113                .getContentTransferEncoding(), binaryBody);
114
115        writeBody(body, encOut);
116
117        // close if wrapped (base64 or quoted-printable)
118        if (encOut != out)
119            encOut.close();
120    }
121
122    /**
123     * Write the specified <code>Message</code> to the specified
124     * <code>OutputStream</code>.
125     *
126     * @param entity
127     *            the <code>Message</code> to write.
128     * @param out
129     *            the OutputStream to write to.
130     * @throws IOException
131     *             if an I/O error occurs.
132     */
133    public void writeMessage(Message message, OutputStream out) throws IOException {
134        writeEntity(message, out);
135    }
136   
137    /**
138     * Write the specified <code>Multipart</code> to the specified
139     * <code>OutputStream</code>.
140     *
141     * @param multipart
142     *            the <code>Multipart</code> to write.
143     * @param out
144     *            the OutputStream to write to.
145     * @throws IOException
146     *             if an I/O error occurs.
147     */
148    public void writeMultipart(Multipart multipart, OutputStream out)
149            throws IOException {
150        ContentTypeField contentType = getContentType(multipart);
151
152        ByteSequence boundary = getBoundary(contentType);
153
154        ByteSequence preamble;
155        ByteSequence epilogue;
156        if (multipart instanceof MultipartImpl) {
157            preamble = ((MultipartImpl) multipart).getPreambleRaw();
158            epilogue = ((MultipartImpl) multipart).getEpilogueRaw();
159        } else {
160            preamble = multipart.getPreamble() != null ? ContentUtil.encode(multipart.getPreamble()) : null;
161            epilogue = multipart.getEpilogue() != null ? ContentUtil.encode(multipart.getEpilogue()) : null;
162        }
163        if (preamble != null) {
164            writeBytes(preamble, out);
165            out.write(CRLF);
166        }
167
168        for (Entity bodyPart : multipart.getBodyParts()) {
169            out.write(DASHES);
170            writeBytes(boundary, out);
171            out.write(CRLF);
172
173            writeEntity(bodyPart, out);
174            out.write(CRLF);
175        }
176
177        out.write(DASHES);
178        writeBytes(boundary, out);
179        out.write(DASHES);
180        out.write(CRLF);
181        if (epilogue != null) {
182            writeBytes(epilogue, out);
183        }
184    }
185
186    /**
187     * Write the specified <code>Field</code> to the specified
188     * <code>OutputStream</code>.
189     *
190     * @param field
191     *            the <code>Field</code> to write.
192     * @param out
193     *            the OutputStream to write to.
194     * @throws IOException
195     *             if an I/O error occurs.
196     */
197    public void writeField(Field field, OutputStream out) throws IOException {
198        ByteSequence raw = null;
199        if (field instanceof FieldRawData) {
200            raw = ((FieldRawData) field).getRaw();
201        }
202        if (raw == null) {
203            StringBuilder buf = new StringBuilder();
204            buf.append(field.getName());
205            buf.append(": ");
206            String body = field.getBody();
207            if (body != null) {
208                buf.append(body);
209            }
210            raw = ContentUtil.encode(MimeUtil.fold(buf.toString(), 0));
211        }
212        writeBytes(raw, out);
213        out.write(CRLF);
214    }
215
216    /**
217     * Write the specified <code>Header</code> to the specified
218     * <code>OutputStream</code>.
219     *
220     * @param header
221     *            the <code>Header</code> to write.
222     * @param out
223     *            the OutputStream to write to.
224     * @throws IOException
225     *             if an I/O error occurs.
226     */
227    public void writeHeader(Header header, OutputStream out) throws IOException {
228        for (Field field : header) {
229            writeField(field, out);
230        }
231
232        out.write(CRLF);
233    }
234
235    protected OutputStream encodeStream(OutputStream out, String encoding,
236            boolean binaryBody) throws IOException {
237        if (MimeUtil.isBase64Encoding(encoding)) {
238            return CodecUtil.wrapBase64(out);
239        } else if (MimeUtil.isQuotedPrintableEncoded(encoding)) {
240            return CodecUtil.wrapQuotedPrintable(out, binaryBody);
241        } else {
242            return out;
243        }
244    }
245
246    private ContentTypeField getContentType(Multipart multipart) {
247        Entity parent = multipart.getParent();
248        if (parent == null)
249            throw new IllegalArgumentException(
250                    "Missing parent entity in multipart");
251
252        Header header = parent.getHeader();
253        if (header == null)
254            throw new IllegalArgumentException(
255                    "Missing header in parent entity");
256
257        ContentTypeField contentType = (ContentTypeField) header
258                .getField(FieldName.CONTENT_TYPE);
259        if (contentType == null)
260            throw new IllegalArgumentException(
261                    "Content-Type field not specified");
262
263        return contentType;
264    }
265
266    private ByteSequence getBoundary(ContentTypeField contentType) {
267        String boundary = contentType.getBoundary();
268        if (boundary == null)
269            throw new IllegalArgumentException(
270                    "Multipart boundary not specified");
271
272        return ContentUtil.encode(boundary);
273    }
274
275    private void writeBytes(ByteSequence byteSequence, OutputStream out)
276            throws IOException {
277        if (byteSequence instanceof ByteArrayBuffer) {
278            ByteArrayBuffer bab = (ByteArrayBuffer) byteSequence;
279            out.write(bab.buffer(), 0, bab.length());
280        } else {
281            out.write(byteSequence.toByteArray());
282        }
283    }
284
285}
Note: See TracBrowser for help on using the repository browser.