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