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 
20 package org.apache.james.mime4j.message;
21 
22 import java.io.BufferedWriter;
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.io.OutputStreamWriter;
26 import java.util.Collections;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30 
31 import org.apache.james.mime4j.field.ContentTypeField;
32 import org.apache.james.mime4j.field.Field;
33 import org.apache.james.mime4j.util.CharsetUtil;
34 
35 /**
36  * Represents a MIME multipart body (see RFC 2045).A multipart body has a
37  * ordered list of body parts. The multipart body also has a preamble and
38  * epilogue. The preamble consists of whatever characters appear before the
39  * first body part while the epilogue consists of whatever characters come
40  * after the last body part.
41  *
42  *
43  * @version $Id: Multipart.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
44  */
45 public class Multipart implements Body {
46     private String preamble = "";
47     private String epilogue = "";
48     private List<BodyPart> bodyParts = new LinkedList<BodyPart>();
49     private Entity parent = null;
50     private String subType = "alternative";
51 
52     /**
53      * Creates a new empty <code>Multipart</code> instance.
54      */
Multipart()55     public Multipart() {
56     }
57 
58     /**
59      * Gets the multipart sub-type. E.g. <code>alternative</code> (the default)
60      * or <code>parallel</code>. See RFC 2045 for common sub-types and their
61      * meaning.
62      *
63      * @return the multipart sub-type.
64      */
getSubType()65     public String getSubType() {
66         return subType;
67     }
68 
69     /**
70      * Sets the multipart sub-type. E.g. <code>alternative</code>
71      * or <code>parallel</code>. See RFC 2045 for common sub-types and their
72      * meaning.
73      *
74      * @param subType the sub-type.
75      */
setSubType(String subType)76     public void setSubType(String subType) {
77         this.subType = subType;
78     }
79 
80     /**
81      * @see org.apache.james.mime4j.message.Body#getParent()
82      */
getParent()83     public Entity getParent() {
84         return parent;
85     }
86 
87     /**
88      * @see org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
89      */
setParent(Entity parent)90     public void setParent(Entity parent) {
91         this.parent = parent;
92         for (Iterator<BodyPart> it = bodyParts.iterator(); it.hasNext();) {
93             it.next().setParent(parent);
94         }
95     }
96 
97     /**
98      * Gets the epilogue.
99      *
100      * @return the epilogue.
101      */
getEpilogue()102     public String getEpilogue() {
103         return epilogue;
104     }
105 
106     /**
107      * Sets the epilogue.
108      *
109      * @param epilogue the epilogue.
110      */
setEpilogue(String epilogue)111     public void setEpilogue(String epilogue) {
112         this.epilogue = epilogue;
113     }
114 
115     /**
116      * Gets the list of body parts. The list is immutable.
117      *
118      * @return the list of <code>BodyPart</code> objects.
119      */
getBodyParts()120     public List<BodyPart> getBodyParts() {
121         return Collections.unmodifiableList(bodyParts);
122     }
123 
124     /**
125      * Sets the list of body parts.
126      *
127      * @param bodyParts the new list of <code>BodyPart</code> objects.
128      */
setBodyParts(List<BodyPart> bodyParts)129     public void setBodyParts(List<BodyPart> bodyParts) {
130         this.bodyParts = bodyParts;
131         for (Iterator<BodyPart> it = bodyParts.iterator(); it.hasNext();) {
132             it.next().setParent(parent);
133         }
134     }
135 
136     /**
137      * Adds a body part to the end of the list of body parts.
138      *
139      * @param bodyPart the body part.
140      */
addBodyPart(BodyPart bodyPart)141     public void addBodyPart(BodyPart bodyPart) {
142         bodyParts.add(bodyPart);
143         bodyPart.setParent(parent);
144     }
145 
146     /**
147      * Gets the preamble.
148      *
149      * @return the preamble.
150      */
getPreamble()151     public String getPreamble() {
152         return preamble;
153     }
154 
155     /**
156      * Sets the preamble.
157      *
158      * @param preamble the preamble.
159      */
setPreamble(String preamble)160     public void setPreamble(String preamble) {
161         this.preamble = preamble;
162     }
163 
164     /**
165      *
166      * @see org.apache.james.mime4j.message.Body#writeTo(java.io.OutputStream)
167      */
writeTo(OutputStream out)168     public void writeTo(OutputStream out) throws IOException {
169         String boundary = getBoundary();
170         List<BodyPart> bodyParts = getBodyParts();
171 
172         BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, CharsetUtil.getCharset(getCharset())),8192);
173 
174         writer.write(getPreamble() + "\r\n");
175 
176         for (int i = 0; i < bodyParts.size(); i++) {
177             writer.write(boundary + "\r\n");
178             bodyParts.get(i).writeTo(out);
179         }
180 
181         writer.write(getEpilogue() + "\r\n");
182         writer.write(boundary + "--" + "\r\n");
183 
184     }
185 
186     /**
187      * Return the boundory of the parent Entity
188      *
189      * @return boundery
190      */
getBoundary()191     private String getBoundary() {
192         Entity e = getParent();
193         ContentTypeField cField = (ContentTypeField) e.getHeader().getField(
194                 Field.CONTENT_TYPE);
195         return cField.getBoundary();
196     }
197 
getCharset()198     private String getCharset() {
199         Entity e = getParent();
200         String charString = ((ContentTypeField) e.getHeader().getField(Field.CONTENT_TYPE)).getCharset();
201         return charString;
202     }
203 }
204