1 /************************************************************************
2 * Copyright (c) 2000-2006 The Apache Software Foundation. *
3 * All rights reserved. *
4 * ------------------------------------------------------------------- *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
6 * may not use this file except in compliance with the License. You *
7 * may obtain a copy of the License at: *
8 * *
9 * http://www.apache.org/licenses/LICENSE-2.0 *
10 * *
11 * Unless required by applicable law or agreed to in writing, software *
12 * distributed under the License is distributed on an "AS IS" BASIS, *
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14 * implied. See the License for the specific language governing *
15 * permissions and limitations under the License. *
16 ***********************************************************************/
17 package org.apache.james.core;
18
19 import org.apache.james.util.InternetPrintWriter;
20 import org.apache.james.util.io.IOUtil;
21
22 import javax.activation.UnsupportedDataTypeException;
23 import javax.mail.MessagingException;
24 import javax.mail.internet.MimeMessage;
25 import javax.mail.internet.MimeUtility;
26
27 import java.io.BufferedWriter;
28 import java.io.ByteArrayInputStream;
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.io.OutputStreamWriter;
34 import java.io.PrintWriter;
35 import java.util.Enumeration;
36
37 /***
38 * Utility class to provide optimized write methods for the various MimeMessage
39 * implementations.
40 */
41 public class MimeMessageUtil {
42
43 /***
44 * Convenience method to take any MimeMessage and write the headers and body to two
45 * different output streams
46 */
47 public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs) throws IOException, MessagingException {
48 writeTo(message, headerOs, bodyOs, null);
49 }
50
51 /***
52 * Convenience method to take any MimeMessage and write the headers and body to two
53 * different output streams, with an ignore list
54 */
55 public static void writeTo(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
56 MimeMessage testMessage = message;
57 if (message instanceof MimeMessageCopyOnWriteProxy) {
58 MimeMessageCopyOnWriteProxy wr = (MimeMessageCopyOnWriteProxy) message;
59 testMessage = wr.getWrappedMessage();
60 }
61 if (testMessage instanceof MimeMessageWrapper) {
62 MimeMessageWrapper wrapper = (MimeMessageWrapper)testMessage;
63 if (!wrapper.isModified()) {
64 wrapper.writeTo(headerOs, bodyOs, ignoreList);
65 return;
66 }
67 }
68 writeToInternal(message, headerOs, bodyOs, ignoreList);
69 }
70
71 /***
72 * @param message
73 * @param headerOs
74 * @param bodyOs
75 * @param ignoreList
76 * @throws MessagingException
77 * @throws IOException
78 * @throws UnsupportedDataTypeException
79 */
80 public static void writeToInternal(MimeMessage message, OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws MessagingException, IOException, UnsupportedDataTypeException {
81 if(message.getMessageID() == null) {
82 message.saveChanges();
83 }
84
85 writeHeadersTo(message, headerOs, ignoreList);
86
87
88 writeMessageBodyTo(message, bodyOs);
89 }
90
91 public static void writeMessageBodyTo(MimeMessage message, OutputStream bodyOs) throws IOException, UnsupportedDataTypeException, MessagingException {
92 OutputStream bos;
93 InputStream bis;
94
95 try {
96
97
98
99
100 bos = MimeUtility.encode(bodyOs, message.getEncoding());
101 bis = message.getInputStream();
102 } catch(UnsupportedDataTypeException udte) {
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 try {
124 bis = message.getRawInputStream();
125 bos = bodyOs;
126 } catch(javax.mail.MessagingException _) {
127 throw udte;
128 }
129 }
130 catch(javax.mail.MessagingException me) {
131
132
133
134
135
136
137
138
139
140
141 try {
142 bis = message.getRawInputStream();
143 bos = bodyOs;
144 } catch(javax.mail.MessagingException _) {
145 throw me;
146 }
147 }
148
149 try {
150 copyStream(bis, bos);
151 }
152 finally {
153 IOUtil.shutdownStream(bis);
154 }
155 }
156
157 /***
158 * Convenience method to copy streams
159 */
160 public static void copyStream(InputStream in, OutputStream out) throws IOException {
161
162
163 byte[] block = new byte[1024];
164 int read = 0;
165 while ((read = in.read(block)) > -1) {
166 out.write(block, 0, read);
167 }
168 out.flush();
169 }
170
171
172 /***
173 * Write the message headers to the given outputstream
174 *
175 * @param message
176 * @param headerOs
177 * @param ignoreList
178 * @throws MessagingException
179 */
180 private static void writeHeadersTo(MimeMessage message, OutputStream headerOs, String[] ignoreList) throws MessagingException {
181
182 Enumeration headers = message.getNonMatchingHeaderLines(ignoreList);
183 writeHeadersTo(headers, headerOs);
184 }
185
186 /***
187 * Write the message headers to the given outputstream
188 *
189 * @param message
190 * @param headerOs
191 * @param ignoreList
192 * @throws MessagingException
193 */
194 public static void writeHeadersTo(Enumeration headers, OutputStream headerOs) throws MessagingException {
195 PrintWriter hos = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(headerOs), 512), true);
196 while (headers.hasMoreElements()) {
197 hos.println((String)headers.nextElement());
198 }
199
200 hos.println();
201 hos.flush();
202 }
203
204 /***
205 * @param message
206 * @param ignoreList
207 * @return
208 * @throws MessagingException
209 */
210 public static InputStream getHeadersInputStream(MimeMessage message, String[] ignoreList) throws MessagingException {
211 ByteArrayOutputStream bo = new ByteArrayOutputStream();
212 writeHeadersTo(message,bo,ignoreList);
213 return new ByteArrayInputStream(bo.toByteArray());
214 }
215
216
217 /***
218 * Slow method to calculate the exact size of a message!
219 */
220 private static final class SizeCalculatorOutputStream extends OutputStream {
221 long size = 0;
222
223 public void write(int arg0) throws IOException {
224 size++;
225 }
226
227 public long getSize() {
228 return size;
229 }
230
231 public void write(byte[] arg0, int arg1, int arg2) throws IOException {
232 size += arg2;
233 }
234
235 public void write(byte[] arg0) throws IOException {
236 size += arg0.length;
237 }
238 }
239
240 /***
241 * @return size of full message including headers
242 *
243 * @throws MessagingException if a problem occours while computing the message size
244 */
245 public static long getMessageSize(MimeMessage message) throws MessagingException {
246
247
248 long size = -1;
249
250 if (message instanceof MimeMessageWrapper) {
251 MimeMessageWrapper wrapper = (MimeMessageWrapper) message;
252 size = wrapper.getMessageSize();
253 } else if (message instanceof MimeMessageCopyOnWriteProxy) {
254 MimeMessageCopyOnWriteProxy wrapper = (MimeMessageCopyOnWriteProxy) message;
255 size = wrapper.getMessageSize();
256 }
257
258 if (size == -1) {
259 size = calculateMessageSize(message);
260 }
261
262 return size;
263 }
264
265 /***
266 * @param message
267 * @return the calculated size
268 * @throws MessagingException
269 */
270 public static long calculateMessageSize(MimeMessage message) throws MessagingException {
271 long size;
272
273
274
275 size = message.getSize();
276 if (size != -1) {
277 Enumeration e = message.getAllHeaderLines();
278 if (e.hasMoreElements()) {
279 size += 2;
280 }
281 while (e.hasMoreElements()) {
282
283 size += ((String) e.nextElement()).length()+2;
284 }
285 }
286
287
288 if (size == -1) {
289 SizeCalculatorOutputStream out = new SizeCalculatorOutputStream();
290 try {
291 message.writeTo(out);
292 } catch (IOException e) {
293
294 throw new MessagingException("IOException wrapped by getMessageSize",e);
295 }
296 size = out.getSize();
297 }
298 return size;
299 }
300
301
302 }