1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.james.mime4j.message;
21
22 import java.io.IOException;
23 import java.io.OutputStream;
24
25 import org.apache.james.mime4j.codec.CodecUtil;
26 import org.apache.james.mime4j.field.ContentTypeField;
27 import org.apache.james.mime4j.field.FieldName;
28 import org.apache.james.mime4j.parser.Field;
29 import org.apache.james.mime4j.util.ByteArrayBuffer;
30 import org.apache.james.mime4j.util.ByteSequence;
31 import org.apache.james.mime4j.util.ContentUtil;
32 import org.apache.james.mime4j.util.MimeUtil;
33
34
35
36
37
38
39
40
41
42
43 public class MessageWriter {
44
45 private static final byte[] CRLF = { '\r', '\n' };
46 private static final byte[] DASHES = { '-', '-' };
47
48
49
50
51 public static final MessageWriter DEFAULT = new MessageWriter();
52
53
54
55
56 protected MessageWriter() {
57 }
58
59
60
61
62
63
64
65
66
67
68
69
70 public void writeBody(Body body, OutputStream out) throws IOException {
71 if (body instanceof Message) {
72 writeEntity((Message) body, out);
73 } else if (body instanceof Multipart) {
74 writeMultipart((Multipart) body, out);
75 } else if (body instanceof SingleBody) {
76 ((SingleBody) body).writeTo(out);
77 } else
78 throw new IllegalArgumentException("Unsupported body class");
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92 public void writeEntity(Entity entity, OutputStream out) throws IOException {
93 final Header header = entity.getHeader();
94 if (header == null)
95 throw new IllegalArgumentException("Missing header");
96
97 writeHeader(header, out);
98
99 final Body body = entity.getBody();
100 if (body == null)
101 throw new IllegalArgumentException("Missing body");
102
103 boolean binaryBody = body instanceof BinaryBody;
104 OutputStream encOut = encodeStream(out, entity
105 .getContentTransferEncoding(), binaryBody);
106
107 writeBody(body, encOut);
108
109
110 if (encOut != out)
111 encOut.close();
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125 public void writeMultipart(Multipart multipart, OutputStream out)
126 throws IOException {
127 ContentTypeField contentType = getContentType(multipart);
128
129 ByteSequence boundary = getBoundary(contentType);
130
131 writeBytes(multipart.getPreambleRaw(), out);
132 out.write(CRLF);
133
134 for (BodyPart bodyPart : multipart.getBodyParts()) {
135 out.write(DASHES);
136 writeBytes(boundary, out);
137 out.write(CRLF);
138
139 writeEntity(bodyPart, out);
140 out.write(CRLF);
141 }
142
143 out.write(DASHES);
144 writeBytes(boundary, out);
145 out.write(DASHES);
146 out.write(CRLF);
147
148 writeBytes(multipart.getEpilogueRaw(), out);
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162 public void writeHeader(Header header, OutputStream out) throws IOException {
163 for (Field field : header) {
164 writeBytes(field.getRaw(), out);
165 out.write(CRLF);
166 }
167
168 out.write(CRLF);
169 }
170
171 protected OutputStream encodeStream(OutputStream out, String encoding,
172 boolean binaryBody) throws IOException {
173 if (MimeUtil.isBase64Encoding(encoding)) {
174 return CodecUtil.wrapBase64(out);
175 } else if (MimeUtil.isQuotedPrintableEncoded(encoding)) {
176 return CodecUtil.wrapQuotedPrintable(out, binaryBody);
177 } else {
178 return out;
179 }
180 }
181
182 private ContentTypeField getContentType(Multipart multipart) {
183 Entity parent = multipart.getParent();
184 if (parent == null)
185 throw new IllegalArgumentException(
186 "Missing parent entity in multipart");
187
188 Header header = parent.getHeader();
189 if (header == null)
190 throw new IllegalArgumentException(
191 "Missing header in parent entity");
192
193 ContentTypeField contentType = (ContentTypeField) header
194 .getField(FieldName.CONTENT_TYPE);
195 if (contentType == null)
196 throw new IllegalArgumentException(
197 "Content-Type field not specified");
198
199 return contentType;
200 }
201
202 private ByteSequence getBoundary(ContentTypeField contentType) {
203 String boundary = contentType.getBoundary();
204 if (boundary == null)
205 throw new IllegalArgumentException(
206 "Multipart boundary not specified");
207
208 return ContentUtil.encode(boundary);
209 }
210
211 private void writeBytes(ByteSequence byteSequence, OutputStream out)
212 throws IOException {
213 if (byteSequence instanceof ByteArrayBuffer) {
214 ByteArrayBuffer bab = (ByteArrayBuffer) byteSequence;
215 out.write(bab.buffer(), 0, bab.length());
216 } else {
217 out.write(byteSequence.toByteArray());
218 }
219 }
220
221 }