1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package javax.mail.internet;
21
22 import java.io.BufferedOutputStream;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.FileOutputStream;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.UnsupportedEncodingException;
31 import java.util.Enumeration;
32
33 import javax.activation.DataHandler;
34 import javax.activation.FileDataSource;
35 import javax.mail.BodyPart;
36 import javax.mail.MessagingException;
37 import javax.mail.Multipart;
38 import javax.mail.Part;
39 import javax.mail.internet.HeaderTokenizer.Token;
40 import javax.swing.text.AbstractDocument.Content;
41
42 import org.apache.geronimo.mail.util.ASCIIUtil;
43 import org.apache.geronimo.mail.util.SessionUtil;
44
45
46
47
48 public class MimeBodyPart extends BodyPart implements MimePart {
49
50 private static final String MIME_DECODEFILENAME = "mail.mime.decodefilename";
51 private static final String MIME_ENCODEFILENAME = "mail.mime.encodefilename";
52 private static final String MIME_SETDEFAULTTEXTCHARSET = "mail.mime.setdefaulttextcharset";
53 private static final String MIME_SETCONTENTTYPEFILENAME = "mail.mime.setcontenttypefilename";
54
55
56
57
58
59 protected DataHandler dh;
60
61
62
63 protected byte content[];
64
65
66
67
68
69 protected InputStream contentStream;
70
71
72
73 protected InternetHeaders headers;
74
75 public MimeBodyPart() {
76 headers = new InternetHeaders();
77 }
78
79 public MimeBodyPart(InputStream in) throws MessagingException {
80 headers = new InternetHeaders(in);
81 ByteArrayOutputStream baos = new ByteArrayOutputStream();
82 byte[] buffer = new byte[1024];
83 int count;
84 try {
85 while((count = in.read(buffer, 0, 1024)) > 0)
86 baos.write(buffer, 0, count);
87 } catch (IOException e) {
88 throw new MessagingException(e.toString(),e);
89 }
90 content = baos.toByteArray();
91 }
92
93 public MimeBodyPart(InternetHeaders headers, byte[] content) throws MessagingException {
94 this.headers = headers;
95 this.content = content;
96 }
97
98
99
100
101
102
103
104
105
106
107 public int getSize() throws MessagingException {
108 if (content != null) {
109 return content.length;
110 }
111 if (contentStream != null) {
112 try {
113 int size = contentStream.available();
114 if (size > 0) {
115 return size;
116 }
117 } catch (IOException e) {
118 }
119 }
120 return -1;
121 }
122
123 public int getLineCount() throws MessagingException {
124 return -1;
125 }
126
127 public String getContentType() throws MessagingException {
128 String value = getSingleHeader("Content-Type");
129 if (value == null) {
130 value = "text/plain";
131 }
132 return value;
133 }
134
135
136
137
138
139
140
141
142
143
144 public boolean isMimeType(String type) throws MessagingException {
145 return new ContentType(getContentType()).match(type);
146 }
147
148
149
150
151
152
153
154
155
156 public String getDisposition() throws MessagingException {
157 String disp = getSingleHeader("Content-Disposition");
158 if (disp != null) {
159 return new ContentDisposition(disp).getDisposition();
160 }
161 return null;
162 }
163
164
165
166
167
168
169
170
171
172
173 public void setDisposition(String disposition) throws MessagingException {
174 if (disposition == null) {
175 removeHeader("Content-Disposition");
176 }
177 else {
178
179 String currentHeader = getSingleHeader("Content-Disposition");
180 if (currentHeader != null) {
181 ContentDisposition content = new ContentDisposition(currentHeader);
182 content.setDisposition(disposition);
183 setHeader("Content-Disposition", content.toString());
184 }
185 else {
186
187 setHeader("Content-Disposition", disposition);
188 }
189 }
190 }
191
192
193
194
195
196
197
198
199 public String getEncoding() throws MessagingException {
200
201 String encoding = getSingleHeader("Content-Transfer-Encoding");
202 if (encoding != null) {
203
204
205 HeaderTokenizer tokenizer = new HeaderTokenizer(encoding, HeaderTokenizer.MIME);
206
207 Token token = tokenizer.next();
208 while (token.getType() != Token.EOF) {
209
210 if (token.getType() == Token.ATOM) {
211 return token.getValue();
212 }
213 }
214
215
216 return encoding;
217 }
218
219 return null;
220 }
221
222
223
224
225
226
227
228
229
230 public String getContentID() throws MessagingException {
231 return getSingleHeader("Content-ID");
232 }
233
234 public void setContentID(String cid) throws MessagingException {
235 setOrRemoveHeader("Content-ID", cid);
236 }
237
238 public String getContentMD5() throws MessagingException {
239 return getSingleHeader("Content-MD5");
240 }
241
242 public void setContentMD5(String md5) throws MessagingException {
243 setHeader("Content-MD5", md5);
244 }
245
246 public String[] getContentLanguage() throws MessagingException {
247 return getHeader("Content-Language");
248 }
249
250 public void setContentLanguage(String[] languages) throws MessagingException {
251 if (languages == null) {
252 removeHeader("Content-Language");
253 } else if (languages.length == 1) {
254 setHeader("Content-Language", languages[0]);
255 } else {
256 StringBuffer buf = new StringBuffer(languages.length * 20);
257 buf.append(languages[0]);
258 for (int i = 1; i < languages.length; i++) {
259 buf.append(',').append(languages[i]);
260 }
261 setHeader("Content-Language", buf.toString());
262 }
263 }
264
265 public String getDescription() throws MessagingException {
266 String description = getSingleHeader("Content-Description");
267 if (description != null) {
268 try {
269
270 return MimeUtility.decodeText(MimeUtility.unfold(description));
271 } catch (UnsupportedEncodingException e) {
272
273 }
274 }
275
276 return description;
277 }
278
279 public void setDescription(String description) throws MessagingException {
280 setDescription(description, null);
281 }
282
283 public void setDescription(String description, String charset) throws MessagingException {
284 if (description == null) {
285 removeHeader("Content-Description");
286 }
287 else {
288 try {
289 setHeader("Content-Description", MimeUtility.fold(21, MimeUtility.encodeText(description, charset, null)));
290 } catch (UnsupportedEncodingException e) {
291 throw new MessagingException(e.getMessage(), e);
292 }
293 }
294 }
295
296 public String getFileName() throws MessagingException {
297
298 String disposition = getSingleHeader("Content-Disposition");
299 String filename = null;
300
301 if (disposition != null) {
302 filename = new ContentDisposition(disposition).getParameter("filename");
303 }
304
305
306
307 if (filename == null) {
308 String type = getSingleHeader("Content-Type");
309 if (type != null) {
310 try {
311 filename = new ContentType(type).getParameter("name");
312 } catch (ParseException e) {
313 }
314 }
315 }
316
317 if (filename != null && SessionUtil.getBooleanProperty(MIME_DECODEFILENAME, false)) {
318 try {
319 filename = MimeUtility.decodeText(filename);
320 } catch (UnsupportedEncodingException e) {
321 throw new MessagingException("Unable to decode filename", e);
322 }
323 }
324
325 return filename;
326 }
327
328
329 public void setFileName(String name) throws MessagingException {
330
331
332 if (name != null && SessionUtil.getBooleanProperty(MIME_ENCODEFILENAME, false)) {
333 try {
334 name = MimeUtility.encodeText(name);
335 } catch (UnsupportedEncodingException e) {
336 throw new MessagingException("Unable to encode filename", e);
337 }
338 }
339
340
341 String disposition = getDisposition();
342
343 if (disposition == null) {
344 disposition = Part.ATTACHMENT;
345 }
346
347
348 ContentDisposition contentDisposition = new ContentDisposition(disposition);
349 contentDisposition.setParameter("filename", name);
350
351
352 setHeader("Content-Disposition", contentDisposition.toString());
353
354
355
356 if (SessionUtil.getBooleanProperty(MIME_SETCONTENTTYPEFILENAME, true)) {
357 ContentType type = new ContentType(getContentType());
358 type.setParameter("name", name);
359 setHeader("Content-Type", type.toString());
360 }
361 }
362
363 public InputStream getInputStream() throws MessagingException, IOException {
364 return getDataHandler().getInputStream();
365 }
366
367 protected InputStream getContentStream() throws MessagingException {
368 if (contentStream != null) {
369 return contentStream;
370 }
371
372 if (content != null) {
373 return new ByteArrayInputStream(content);
374 } else {
375 throw new MessagingException("No content");
376 }
377 }
378
379 public InputStream getRawInputStream() throws MessagingException {
380 return getContentStream();
381 }
382
383 public synchronized DataHandler getDataHandler() throws MessagingException {
384 if (dh == null) {
385 dh = new DataHandler(new MimePartDataSource(this));
386 }
387 return dh;
388 }
389
390 public Object getContent() throws MessagingException, IOException {
391 return getDataHandler().getContent();
392 }
393
394 public void setDataHandler(DataHandler handler) throws MessagingException {
395 dh = handler;
396
397
398
399 removeHeader("Content-Type");
400 removeHeader("Content-Transfer-Encoding");
401
402 }
403
404 public void setContent(Object content, String type) throws MessagingException {
405
406 if (content instanceof Multipart) {
407 setContent((Multipart)content);
408 }
409 else {
410 setDataHandler(new DataHandler(content, type));
411 }
412
413 }
414
415 public void setText(String text) throws MessagingException {
416 setText(text, null);
417 }
418
419 public void setText(String text, String charset) throws MessagingException {
420
421 setText(text, charset, "plain");
422 }
423
424
425 public void setText(String text, String charset, String subtype) throws MessagingException {
426
427 if (charset == null) {
428
429 if (!ASCIIUtil.isAscii(text)) {
430 charset = MimeUtility.getDefaultMIMECharset();
431 }
432 else {
433 charset = "us-ascii";
434 }
435 }
436 setContent(text, "text/plain; charset=" + MimeUtility.quote(charset, HeaderTokenizer.MIME));
437 }
438
439 public void setContent(Multipart part) throws MessagingException {
440 setDataHandler(new DataHandler(part, part.getContentType()));
441 part.setParent(this);
442 }
443
444 public void writeTo(OutputStream out) throws IOException, MessagingException {
445 headers.writeTo(out, null);
446
447 out.write('\r');
448 out.write('\n');
449
450 OutputStream encodingStream = MimeUtility.encode(out, getEncoding());
451 getDataHandler().writeTo(encodingStream);
452 encodingStream.flush();
453 }
454
455 public String[] getHeader(String name) throws MessagingException {
456 return headers.getHeader(name);
457 }
458
459 public String getHeader(String name, String delimiter) throws MessagingException {
460 return headers.getHeader(name, delimiter);
461 }
462
463 public void setHeader(String name, String value) throws MessagingException {
464 headers.setHeader(name, value);
465 }
466
467
468
469
470
471
472
473
474
475
476
477 private void setOrRemoveHeader(String name, String value) throws MessagingException {
478 if (value == null) {
479 headers.removeHeader(name);
480 }
481 else {
482 headers.setHeader(name, value);
483 }
484 }
485
486 public void addHeader(String name, String value) throws MessagingException {
487 headers.addHeader(name, value);
488 }
489
490 public void removeHeader(String name) throws MessagingException {
491 headers.removeHeader(name);
492 }
493
494 public Enumeration getAllHeaders() throws MessagingException {
495 return headers.getAllHeaders();
496 }
497
498 public Enumeration getMatchingHeaders(String[] name) throws MessagingException {
499 return headers.getMatchingHeaders(name);
500 }
501
502 public Enumeration getNonMatchingHeaders(String[] name) throws MessagingException {
503 return headers.getNonMatchingHeaders(name);
504 }
505
506 public void addHeaderLine(String line) throws MessagingException {
507 headers.addHeaderLine(line);
508 }
509
510 public Enumeration getAllHeaderLines() throws MessagingException {
511 return headers.getAllHeaderLines();
512 }
513
514 public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
515 return headers.getMatchingHeaderLines(names);
516 }
517
518 public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
519 return headers.getNonMatchingHeaderLines(names);
520 }
521
522 protected void updateHeaders() throws MessagingException {
523 DataHandler handler = getDataHandler();
524
525 try {
526
527 String type = dh.getContentType();
528
529 ContentType content = new ContentType(type);
530
531 if (content.match("multipart/*")) {
532
533 try {
534 MimeMultipart part = (MimeMultipart)handler.getContent();
535 part.updateHeaders();
536 } catch (ClassCastException e) {
537 throw new MessagingException("Message content is not MimeMultipart", e);
538 }
539 }
540 else if (!content.match("message/rfc822")) {
541
542
543 if (getSingleHeader("Content-Transfer-Encoding") == null) {
544 setHeader("Content-Transfer-Encoding", MimeUtility.getEncoding(handler));
545 }
546
547
548 if (getHeader("Content-Type") == null) {
549 if (SessionUtil.getBooleanProperty(MIME_SETDEFAULTTEXTCHARSET, true)) {
550
551 if (content.match("text/*")) {
552
553
554 if (content.getParameter("charset") == null) {
555
556 String encoding = getEncoding();
557
558
559 if (encoding != null && encoding.equalsIgnoreCase("7bit")) {
560 content.setParameter("charset", "us-ascii");
561 }
562 else {
563
564 content.setParameter("charset", MimeUtility.getDefaultMIMECharset());
565 }
566 }
567 }
568 }
569 }
570 }
571
572
573 if (getSingleHeader("Content-Type") == null) {
574
575
576 String disp = getHeader("Content-Disposition", null);
577 if (disp != null) {
578
579 ContentDisposition disposition = new ContentDisposition(disp);
580
581 String filename = disposition.getParameter("filename");
582
583 if (filename != null) {
584 content.setParameter("name", filename);
585 }
586 }
587
588 setHeader("Content-Type", content.toString());
589 }
590
591 } catch (IOException e) {
592 throw new MessagingException("Error updating message headers", e);
593 }
594 }
595
596 private String getSingleHeader(String name) throws MessagingException {
597 String[] values = getHeader(name);
598 if (values == null || values.length == 0) {
599 return null;
600 } else {
601 return values[0];
602 }
603 }
604
605
606
607
608
609
610
611
612
613
614 public void attachFile(File file) throws IOException, MessagingException {
615 FileDataSource dataSource = new FileDataSource(file);
616 setDataHandler(new DataHandler(dataSource));
617 setFileName(dataSource.getName());
618 }
619
620
621
622
623
624
625
626
627
628
629 public void attachFile(String file) throws IOException, MessagingException {
630
631 attachFile(new File(file));
632 }
633
634
635
636
637
638
639
640
641
642
643 public void saveFile(File file) throws IOException, MessagingException {
644 OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
645
646 InputStream in = getInputStream();
647 try {
648 byte[] buffer = new byte[8192];
649 int length;
650 while ((length = in.read(buffer)) > 0) {
651 out.write(buffer, 0, length);
652 }
653 }
654 finally {
655
656 if (in != null) {
657 in.close();
658 }
659 if (out != null) {
660 out.close();
661 }
662 }
663 }
664
665
666
667
668
669
670
671
672
673
674 public void saveFile(String file) throws IOException, MessagingException {
675 saveFile(new File(file));
676 }
677 }