1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.james.core;
23
24 import org.apache.avalon.framework.activity.Disposable;
25 import org.apache.avalon.framework.container.ContainerUtil;
26 import org.apache.james.util.InternetPrintWriter;
27 import org.apache.james.util.io.IOUtil;
28
29 import javax.activation.DataHandler;
30 import javax.mail.MessagingException;
31 import javax.mail.Session;
32 import javax.mail.internet.InternetHeaders;
33 import javax.mail.internet.MimeMessage;
34 import javax.mail.util.SharedByteArrayInputStream;
35
36 import java.io.BufferedWriter;
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.io.LineNumberReader;
42 import java.io.OutputStream;
43 import java.io.OutputStreamWriter;
44 import java.io.PrintWriter;
45 import java.util.Enumeration;
46
47
48
49
50
51
52 public class MimeMessageWrapper
53 extends MimeMessage
54 implements Disposable {
55
56
57
58
59 protected MimeMessageSource source = null;
60
61
62
63
64 protected boolean messageParsed = false;
65
66
67
68
69 protected boolean headersModified = false;
70
71
72
73
74 protected boolean bodyModified = false;
75
76
77
78
79
80 private InputStream sourceIn;
81
82 private MimeMessageWrapper(Session session) throws MessagingException {
83 super(session);
84 this.headers = null;
85 this.modified = false;
86 this.headersModified = false;
87 this.bodyModified = false;
88 }
89
90
91
92
93
94
95
96
97 public MimeMessageWrapper(Session session, MimeMessageSource source) throws MessagingException {
98 this(session);
99 this.source = source;
100 }
101
102
103
104
105
106
107
108
109
110 public MimeMessageWrapper(MimeMessageSource source) throws MessagingException {
111 this(Session.getDefaultInstance(System.getProperties()),source);
112 }
113
114 public MimeMessageWrapper(MimeMessage original) throws MessagingException {
115 this(Session.getDefaultInstance(System.getProperties()));
116 flags = original.getFlags();
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 if (source == null) {
135 ByteArrayOutputStream bos;
136 int size = original.getSize();
137 if (size > 0)
138 bos = new ByteArrayOutputStream(size);
139 else
140 bos = new ByteArrayOutputStream();
141 try {
142 original.writeTo(bos);
143 bos.close();
144 SharedByteArrayInputStream bis =
145 new SharedByteArrayInputStream(bos.toByteArray());
146 parse(bis);
147 bis.close();
148 saved = true;
149 } catch (IOException ex) {
150
151 throw new MessagingException("IOException while copying message",
152 ex);
153 }
154 }
155 }
156
157
158
159
160
161
162 public synchronized String getSourceId() {
163 return source != null ? source.getSourceId() : null;
164 }
165
166
167
168
169
170
171
172 protected synchronized void loadHeaders() throws MessagingException {
173 if (headers != null) {
174
175 return;
176 } else if (source != null) {
177 try {
178 InputStream in = source.getInputStream();
179 try {
180 headers = createInternetHeaders(in);
181 } finally {
182 IOUtil.shutdownStream(in);
183 }
184 } catch (IOException ioe) {
185 throw new MessagingException("Unable to parse headers from stream: " + ioe.getMessage(), ioe);
186 }
187 } else {
188 throw new MessagingException("loadHeaders called for a message with no source, contentStream or stream");
189 }
190 }
191
192
193
194
195
196
197
198 protected synchronized void loadMessage() throws MessagingException {
199 if (messageParsed) {
200
201 return;
202 } else if (source != null) {
203 sourceIn = null;
204 try {
205 sourceIn = source.getInputStream();
206
207 parse(sourceIn);
208
209 saved = true;
210
211 } catch (IOException ioe) {
212 IOUtil.shutdownStream(sourceIn);
213 sourceIn = null;
214 throw new MessagingException("Unable to parse stream: " + ioe.getMessage(), ioe);
215 }
216 } else {
217 throw new MessagingException("loadHeaders called for an unparsed message with no source");
218 }
219 }
220
221
222
223
224
225
226 public synchronized boolean isModified() {
227 return headersModified || bodyModified || modified;
228 }
229
230
231
232
233 public synchronized void writeTo(OutputStream os) throws IOException, MessagingException {
234 if (source != null && !isModified()) {
235
236
237 InputStream in = source.getInputStream();
238 try {
239 MimeMessageUtil.copyStream(in, os);
240 } finally {
241 IOUtil.shutdownStream(in);
242 }
243 } else {
244 writeTo(os, os);
245 }
246 }
247
248
249
250
251 public void writeTo(OutputStream os, String[] ignoreList) throws IOException, MessagingException {
252 writeTo(os, os, ignoreList);
253 }
254
255
256
257
258 public void writeTo(OutputStream headerOs, OutputStream bodyOs) throws IOException, MessagingException {
259 writeTo(headerOs, bodyOs, new String[0]);
260 }
261
262 public synchronized void writeTo(OutputStream headerOs, OutputStream bodyOs, String[] ignoreList) throws IOException, MessagingException {
263 if (source != null && !isModified()) {
264
265
266
267
268 InputStream in = source.getInputStream();
269 try {
270 InternetHeaders headers = new InternetHeaders(in);
271 PrintWriter pos = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(headerOs), 512), true);
272 for (Enumeration e = headers.getNonMatchingHeaderLines(ignoreList); e.hasMoreElements(); ) {
273 String header = (String)e.nextElement();
274 pos.println(header);
275 }
276 pos.println();
277 pos.flush();
278 MimeMessageUtil.copyStream(in, bodyOs);
279 } finally {
280 IOUtil.shutdownStream(in);
281 }
282 } else {
283 MimeMessageUtil.writeToInternal(this, headerOs, bodyOs, ignoreList);
284 }
285 }
286
287
288
289
290
291
292 public int getSize() throws MessagingException {
293 if (!messageParsed) {
294 loadMessage();
295 }
296 return super.getSize();
297 }
298
299
300
301
302
303
304 public int getLineCount() throws MessagingException {
305 InputStream in=null;
306 try{
307 in = getContentStream();
308 }catch(Exception e){
309 return -1;
310 }
311 if (in == null) {
312 return -1;
313 }
314
315
316 try {
317 LineNumberReader counter;
318 if (getEncoding() != null) {
319 counter = new LineNumberReader(new InputStreamReader(in, getEncoding()));
320 } else {
321 counter = new LineNumberReader(new InputStreamReader(in));
322 }
323
324 char[] block = new char[4096];
325 while (counter.read(block) > -1) {
326
327 }
328 return counter.getLineNumber();
329 } catch (IOException ioe) {
330 return -1;
331 } finally {
332 IOUtil.shutdownStream(in);
333 }
334 }
335
336
337
338
339 public long getMessageSize() throws MessagingException {
340 if (source != null && !isModified()) {
341 try {
342 return source.getMessageSize();
343 } catch (IOException ioe) {
344 throw new MessagingException("Error retrieving message size", ioe);
345 }
346 } else {
347 return MimeMessageUtil.calculateMessageSize(this);
348 }
349 }
350
351
352
353
354
355
356 public String[] getHeader(String name) throws MessagingException {
357 if (headers == null) {
358 loadHeaders();
359 }
360 return headers.getHeader(name);
361 }
362
363 public String getHeader(String name, String delimiter) throws MessagingException {
364 if (headers == null) {
365 loadHeaders();
366 }
367 return headers.getHeader(name, delimiter);
368 }
369
370 public Enumeration getAllHeaders() throws MessagingException {
371 if (headers == null) {
372 loadHeaders();
373 }
374 return headers.getAllHeaders();
375 }
376
377 public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
378 if (headers == null) {
379 loadHeaders();
380 }
381 return headers.getMatchingHeaders(names);
382 }
383
384 public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
385 if (headers == null) {
386 loadHeaders();
387 }
388 return headers.getNonMatchingHeaders(names);
389 }
390
391 public Enumeration getAllHeaderLines() throws MessagingException {
392 if (headers == null) {
393 loadHeaders();
394 }
395 return headers.getAllHeaderLines();
396 }
397
398 public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
399 if (headers == null) {
400 loadHeaders();
401 }
402 return headers.getMatchingHeaderLines(names);
403 }
404
405 public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
406 if (headers == null) {
407 loadHeaders();
408 }
409 return headers.getNonMatchingHeaderLines(names);
410 }
411
412
413 private synchronized void checkModifyHeaders() throws MessagingException {
414
415 if (!messageParsed) {
416 loadMessage();
417 }
418
419 if (headers == null) {
420 loadHeaders();
421 }
422 modified = true;
423 saved = false;
424 headersModified = true;
425 }
426
427 public void setHeader(String name, String value) throws MessagingException {
428 checkModifyHeaders();
429 super.setHeader(name, value);
430 }
431
432 public void addHeader(String name, String value) throws MessagingException {
433 checkModifyHeaders();
434 super.addHeader(name, value);
435 }
436
437 public void removeHeader(String name) throws MessagingException {
438 checkModifyHeaders();
439 super.removeHeader(name);
440 }
441
442 public void addHeaderLine(String line) throws MessagingException {
443 checkModifyHeaders();
444 super.addHeaderLine(line);
445 }
446
447
448
449
450
451
452
453
454 public synchronized void setDataHandler(DataHandler arg0) throws MessagingException {
455 modified = true;
456 saved = false;
457 bodyModified = true;
458 super.setDataHandler(arg0);
459 }
460
461
462
463
464 public void dispose() {
465 if (sourceIn != null) {
466 IOUtil.shutdownStream(sourceIn);
467 }
468 if (source != null) {
469 ContainerUtil.dispose(source);
470 }
471 }
472
473
474
475
476 protected synchronized void parse(InputStream is) throws MessagingException {
477
478
479 super.parse(is);
480 messageParsed = true;
481 }
482
483
484
485
486
487
488
489 protected synchronized InternetHeaders createInternetHeaders(InputStream is) throws MessagingException {
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513 MailHeaders newHeaders = new MailHeaders(is);
514
515 if (headers != null) {
516 return headers;
517 } else {
518 return newHeaders;
519 }
520 }
521
522
523
524
525 protected InputStream getContentStream() throws MessagingException {
526 if (!messageParsed) {
527 loadMessage();
528 }
529 return super.getContentStream();
530 }
531
532
533
534
535 public InputStream getRawInputStream() throws MessagingException {
536 if (!messageParsed && !isModified() && source != null) {
537 InputStream is;
538 try {
539 is = source.getInputStream();
540
541 new MailHeaders(is);
542 return is;
543 } catch (IOException e) {
544 throw new MessagingException("Unable to read the stream: " + e.getMessage(), e);
545 }
546 } else return super.getRawInputStream();
547 }
548
549
550
551 }