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.BufferedInputStream;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.ObjectStreamException;
28 import java.io.OutputStream;
29 import java.io.UnsupportedEncodingException;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Date;
33 import java.util.Enumeration;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37
38 import javax.activation.DataHandler;
39 import javax.mail.Address;
40 import javax.mail.Flags;
41 import javax.mail.Folder;
42 import javax.mail.Message;
43 import javax.mail.MessagingException;
44 import javax.mail.Multipart;
45 import javax.mail.Part;
46 import javax.mail.Session;
47 import javax.mail.internet.HeaderTokenizer.Token;
48
49 import org.apache.geronimo.mail.util.ASCIIUtil;
50 import org.apache.geronimo.mail.util.SessionUtil;
51
52
53
54
55 public class MimeMessage extends Message implements MimePart {
56 private static final String MIME_ADDRESS_STRICT = "mail.mime.address.strict";
57 private static final String MIME_DECODEFILENAME = "mail.mime.decodefilename";
58 private static final String MIME_ENCODEFILENAME = "mail.mime.encodefilename";
59
60 private static final String MAIL_ALTERNATES = "mail.alternates";
61 private static final String MAIL_REPLYALLCC = "mail.replyallcc";
62
63
64 private static int messageID = 0;
65
66
67
68
69
70 public static class RecipientType extends Message.RecipientType {
71
72
73
74 public static final RecipientType NEWSGROUPS = new RecipientType("Newsgroups");
75
76 protected RecipientType(String type) {
77 super(type);
78 }
79
80
81
82
83
84
85 protected Object readResolve() throws ObjectStreamException {
86 if (this.type.equals("Newsgroups")) {
87 return NEWSGROUPS;
88 } else {
89 return super.readResolve();
90 }
91 }
92 }
93
94
95
96
97 protected DataHandler dh;
98
99
100
101 protected byte[] content;
102
103
104
105
106
107 protected InputStream contentStream;
108
109
110
111 protected InternetHeaders headers;
112
113
114
115 protected Flags flags;
116
117
118
119
120 protected boolean modified;
121
122
123
124 protected boolean saved;
125
126 private final MailDateFormat dateFormat = new MailDateFormat();
127
128
129
130
131
132
133
134
135 public MimeMessage(Session session) {
136 super(session);
137 headers = new InternetHeaders();
138 flags = new Flags();
139
140 modified = true;
141 saved = false;
142 }
143
144
145
146
147
148
149
150
151 public MimeMessage(Session session, InputStream in) throws MessagingException {
152 this(session);
153 parse(in);
154
155 modified = false;
156
157 saved = true;
158 }
159
160
161
162
163
164
165
166 public MimeMessage(MimeMessage message) throws MessagingException {
167 super(message.session);
168
169
170
171
172
173
174
175
176 ByteArrayOutputStream copy = new ByteArrayOutputStream();
177
178 try {
179
180 message.writeTo(copy);
181 copy.close();
182
183
184 ByteArrayInputStream inData = new ByteArrayInputStream(copy.toByteArray());
185
186 inData.close();
187 parse (inData);
188
189 saved = true;
190
191 modified = false;
192 } catch (IOException e) {
193
194
195
196 throw new MessagingException("Error copying MimeMessage data", e);
197 }
198 }
199
200
201
202
203
204
205
206 protected MimeMessage(Folder folder, int number) {
207 super(folder, number);
208 headers = new InternetHeaders();
209 flags = new Flags();
210
211
212 saved = true;
213
214 modified = true;
215 }
216
217
218
219
220
221
222
223
224
225 protected MimeMessage(Folder folder, InputStream in, int number) throws MessagingException {
226 this(folder, number);
227 parse(in);
228
229 modified = false;
230
231 saved = true;
232 }
233
234
235
236
237
238
239
240
241
242
243
244 protected MimeMessage(Folder folder, InternetHeaders headers, byte[] content, int number) throws MessagingException {
245 this(folder, number);
246 this.headers = headers;
247 this.content = content;
248
249 modified = false;
250 }
251
252
253
254
255
256
257
258 protected void parse(InputStream in) throws MessagingException {
259 in = new BufferedInputStream(in);
260
261 headers = new InternetHeaders(in);
262
263
264
265 ByteArrayOutputStream baos = new ByteArrayOutputStream();
266 try {
267 byte buffer[] = new byte[1024];
268 int count;
269 while ((count = in.read(buffer, 0, 1024)) != -1) {
270 baos.write(buffer, 0, count);
271 }
272 } catch (Exception e) {
273 throw new MessagingException(e.toString(), e);
274 }
275
276 content = baos.toByteArray();
277 }
278
279
280
281
282
283
284
285
286
287
288 public Address[] getFrom() throws MessagingException {
289
290 boolean strict = isStrictAddressing();
291 Address[] result = getHeaderAsInternetAddresses("From", strict);
292 if (result == null) {
293 result = getHeaderAsInternetAddresses("Sender", strict);
294 }
295 return result;
296 }
297
298
299
300
301
302
303
304
305
306
307 public void setFrom(Address address) throws MessagingException {
308 setHeader("From", address);
309 }
310
311
312
313
314
315
316 public void setFrom() throws MessagingException {
317 InternetAddress address = InternetAddress.getLocalAddress(session);
318
319 if (address == null) {
320 throw new MessagingException("No local address defined");
321 }
322 setFrom(address);
323 }
324
325
326
327
328
329
330
331
332 public void addFrom(Address[] addresses) throws MessagingException {
333 addHeader("From", addresses);
334 }
335
336
337
338
339
340
341
342 public Address getSender() throws MessagingException {
343 Address[] addrs = getHeaderAsInternetAddresses("Sender", isStrictAddressing());
344 return addrs != null && addrs.length > 0 ? addrs[0] : null;
345 }
346
347
348
349
350
351
352
353
354
355
356 public void setSender(Address address) throws MessagingException {
357 setHeader("Sender", address);
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374 public Address[] getRecipients(Message.RecipientType type) throws MessagingException {
375
376
377 if (type == RecipientType.NEWSGROUPS) {
378 return getHeaderAsNewsAddresses(getHeaderForRecipientType(type));
379 }
380
381 return getHeaderAsInternetAddresses(getHeaderForRecipientType(type), isStrictAddressing());
382 }
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398 public Address[] getAllRecipients() throws MessagingException {
399 List recipients = new ArrayList();
400 addRecipientsToList(recipients, RecipientType.TO);
401 addRecipientsToList(recipients, RecipientType.CC);
402 addRecipientsToList(recipients, RecipientType.BCC);
403 addRecipientsToList(recipients, RecipientType.NEWSGROUPS);
404
405
406 if (recipients.isEmpty()) {
407 return null;
408 }
409 return (Address[]) recipients.toArray(new Address[recipients.size()]);
410 }
411
412
413
414
415
416
417
418
419
420
421 private void addRecipientsToList(List list, Message.RecipientType type) throws MessagingException {
422
423 Address[] recipients;
424 if (type == RecipientType.NEWSGROUPS) {
425 recipients = getHeaderAsNewsAddresses(getHeaderForRecipientType(type));
426 }
427 else {
428 recipients = getHeaderAsInternetAddresses(getHeaderForRecipientType(type), isStrictAddressing());
429 }
430 if (recipients != null) {
431 list.addAll(Arrays.asList(recipients));
432 }
433 }
434
435
436
437
438
439
440
441
442
443
444 public void setRecipients(Message.RecipientType type, Address[] addresses) throws MessagingException {
445 setHeader(getHeaderForRecipientType(type), addresses);
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459 public void setRecipients(Message.RecipientType type, String address) throws MessagingException {
460 setOrRemoveHeader(getHeaderForRecipientType(type), address);
461 }
462
463
464
465
466
467
468
469
470
471
472 public void addRecipients(Message.RecipientType type, Address[] address) throws MessagingException {
473 addHeader(getHeaderForRecipientType(type), address);
474 }
475
476
477
478
479
480
481
482
483
484 public void addRecipients(Message.RecipientType type, String address) throws MessagingException {
485 addHeader(getHeaderForRecipientType(type), address);
486 }
487
488
489
490
491
492
493
494
495
496 public Address[] getReplyTo() throws MessagingException {
497 Address[] addresses = getHeaderAsInternetAddresses("Reply-To", isStrictAddressing());
498 if (addresses == null) {
499 addresses = getFrom();
500 }
501 return addresses;
502 }
503
504
505
506
507
508
509
510
511
512 public void setReplyTo(Address[] address) throws MessagingException {
513 setHeader("Reply-To", address);
514 }
515
516
517
518
519
520
521
522
523
524
525 public String getSubject() throws MessagingException {
526 String subject = getSingleHeader("Subject");
527 if (subject == null) {
528 return null;
529 } else {
530 try {
531
532 return MimeUtility.decodeText(MimeUtility.unfold(subject));
533 } catch (UnsupportedEncodingException e) {
534
535 }
536 }
537
538 return subject;
539 }
540
541
542
543
544
545
546
547
548
549
550
551
552 public void setSubject(String subject) throws MessagingException {
553
554 setSubject(subject, null);
555 }
556
557 public void setSubject(String subject, String charset) throws MessagingException {
558
559 if (subject == null) {
560 removeHeader("Subject");
561 }
562 else {
563 try {
564 String s = MimeUtility.fold(9, MimeUtility.encodeText(subject, charset, null));
565
566 setHeader("Subject", MimeUtility.fold(9, MimeUtility.encodeText(subject, charset, null)));
567 } catch (UnsupportedEncodingException e) {
568 throw new MessagingException("Encoding error", e);
569 }
570 }
571 }
572
573
574
575
576
577
578
579
580 public Date getSentDate() throws MessagingException {
581 String value = getSingleHeader("Date");
582 if (value == null) {
583 return null;
584 }
585 try {
586 return dateFormat.parse(value);
587 } catch (java.text.ParseException e) {
588 return null;
589 }
590 }
591
592
593
594
595
596
597
598
599
600 public void setSentDate(Date sent) throws MessagingException {
601 setOrRemoveHeader("Date", dateFormat.format(sent));
602 }
603
604
605
606
607
608
609
610
611 public Date getReceivedDate() throws MessagingException {
612 return null;
613 }
614
615
616
617
618
619
620
621
622
623
624 public int getSize() throws MessagingException {
625 if (content != null) {
626 return content.length;
627 }
628 if (contentStream != null) {
629 try {
630 int size = contentStream.available();
631 if (size > 0) {
632 return size;
633 }
634 } catch (IOException e) {
635
636 }
637 }
638 return -1;
639 }
640
641
642
643
644
645
646
647
648
649
650
651 public int getLineCount() throws MessagingException {
652 return -1;
653 }
654
655
656
657
658
659
660
661
662 public String getContentType() throws MessagingException {
663 String value = getSingleHeader("Content-Type");
664 if (value == null) {
665 value = "text/plain";
666 }
667 return value;
668 }
669
670
671
672
673
674
675
676
677
678
679
680 public boolean isMimeType(String type) throws MessagingException {
681 return new ContentType(getContentType()).match(type);
682 }
683
684
685
686
687
688
689
690
691
692 public String getDisposition() throws MessagingException {
693 String disp = getSingleHeader("Content-Disposition");
694 if (disp != null) {
695 return new ContentDisposition(disp).getDisposition();
696 }
697 return null;
698 }
699
700
701
702
703
704
705
706
707
708
709
710 public void setDisposition(String disposition) throws MessagingException {
711 if (disposition == null) {
712 removeHeader("Content-Disposition");
713 }
714 else {
715
716 String currentHeader = getSingleHeader("Content-Disposition");
717 if (currentHeader != null) {
718 ContentDisposition content = new ContentDisposition(currentHeader);
719 content.setDisposition(disposition);
720 setHeader("Content-Disposition", content.toString());
721 }
722 else {
723
724 setHeader("Content-Disposition", disposition);
725 }
726 }
727 }
728
729
730
731
732
733
734
735
736 public String getEncoding() throws MessagingException {
737
738 String encoding = getSingleHeader("Content-Transfer-Encoding");
739 if (encoding != null) {
740
741
742 HeaderTokenizer tokenizer = new HeaderTokenizer(encoding, HeaderTokenizer.MIME);
743
744 Token token = tokenizer.next();
745 while (token.getType() != Token.EOF) {
746
747 if (token.getType() == Token.ATOM) {
748 return token.getValue();
749 }
750 }
751
752
753 return encoding;
754 }
755
756 return null;
757 }
758
759
760
761
762
763
764
765
766 public String getContentID() throws MessagingException {
767 return getSingleHeader("Content-ID");
768 }
769
770 public void setContentID(String cid) throws MessagingException {
771 setOrRemoveHeader("Content-ID", cid);
772 }
773
774 public String getContentMD5() throws MessagingException {
775 return getSingleHeader("Content-MD5");
776 }
777
778 public void setContentMD5(String md5) throws MessagingException {
779 setOrRemoveHeader("Content-MD5", md5);
780 }
781
782 public String getDescription() throws MessagingException {
783 String description = getSingleHeader("Content-Description");
784 if (description != null) {
785 try {
786
787 return MimeUtility.decodeText(MimeUtility.unfold(description));
788 } catch (UnsupportedEncodingException e) {
789
790 }
791 }
792
793 return description;
794 }
795
796 public void setDescription(String description) throws MessagingException {
797 setDescription(description, null);
798 }
799
800 public void setDescription(String description, String charset) throws MessagingException {
801 if (description == null) {
802 removeHeader("Content-Description");
803 }
804 else {
805 try {
806 setHeader("Content-Description", MimeUtility.fold(21, MimeUtility.encodeText(description, charset, null)));
807 } catch (UnsupportedEncodingException e) {
808 throw new MessagingException(e.getMessage(), e);
809 }
810 }
811
812 }
813
814 public String[] getContentLanguage() throws MessagingException {
815 return getHeader("Content-Language");
816 }
817
818 public void setContentLanguage(String[] languages) throws MessagingException {
819 if (languages == null) {
820 removeHeader("Content-Language");
821 } else if (languages.length == 1) {
822 setHeader("Content-Language", languages[0]);
823 } else {
824 StringBuffer buf = new StringBuffer(languages.length * 20);
825 buf.append(languages[0]);
826 for (int i = 1; i < languages.length; i++) {
827 buf.append(',').append(languages[i]);
828 }
829 setHeader("Content-Language", buf.toString());
830 }
831 }
832
833 public String getMessageID() throws MessagingException {
834 return getSingleHeader("Message-ID");
835 }
836
837 public String getFileName() throws MessagingException {
838
839 String disposition = getDisposition();
840 String filename = null;
841
842 if (disposition != null) {
843 filename = new ContentDisposition(disposition).getParameter("filename");
844 }
845
846
847
848 if (filename == null) {
849 String type = getContentType();
850 if (type != null) {
851 try {
852 filename = new ContentType(type).getParameter("name");
853 } catch (ParseException e) {
854 }
855 }
856 }
857
858 if (filename != null && SessionUtil.getBooleanProperty(session, MIME_DECODEFILENAME, false)) {
859 try {
860 filename = MimeUtility.decodeText(filename);
861 } catch (UnsupportedEncodingException e) {
862 throw new MessagingException("Unable to decode filename", e);
863 }
864 }
865
866 return filename;
867 }
868
869
870 public void setFileName(String name) throws MessagingException {
871
872
873 if (name != null && SessionUtil.getBooleanProperty(session, MIME_ENCODEFILENAME, false)) {
874 try {
875 name = MimeUtility.encodeText(name);
876 } catch (UnsupportedEncodingException e) {
877 throw new MessagingException("Unable to encode filename", e);
878 }
879 }
880
881
882 String disposition = getDisposition();
883
884 if (disposition == null) {
885 disposition = Part.ATTACHMENT;
886 }
887
888 ContentDisposition contentDisposition = new ContentDisposition(disposition);
889 contentDisposition.setParameter("filename", name);
890
891
892 setDisposition(contentDisposition.toString());
893 }
894
895 public InputStream getInputStream() throws MessagingException, IOException {
896 return getDataHandler().getInputStream();
897 }
898
899 protected InputStream getContentStream() throws MessagingException {
900 if (contentStream != null) {
901 return contentStream;
902 }
903
904 if (content != null) {
905 return new ByteArrayInputStream(content);
906 } else {
907 throw new MessagingException("No content");
908 }
909 }
910
911 public InputStream getRawInputStream() throws MessagingException {
912 return getContentStream();
913 }
914
915 public synchronized DataHandler getDataHandler() throws MessagingException {
916 if (dh == null) {
917 dh = new DataHandler(new MimePartDataSource(this));
918 }
919 return dh;
920 }
921
922 public Object getContent() throws MessagingException, IOException {
923 return getDataHandler().getContent();
924 }
925
926 public void setDataHandler(DataHandler handler) throws MessagingException {
927 dh = handler;
928
929
930
931 removeHeader("Content-Type");
932 removeHeader("Content-Transfer-Encoding");
933 }
934
935 public void setContent(Object content, String type) throws MessagingException {
936 setDataHandler(new DataHandler(content, type));
937 }
938
939 public void setText(String text) throws MessagingException {
940 setText(text, null, "plain");
941 }
942
943 public void setText(String text, String charset) throws MessagingException {
944 setText(text, charset, "plain");
945 }
946
947
948 public void setText(String text, String charset, String subtype) throws MessagingException {
949
950 if (charset == null) {
951
952 if (!ASCIIUtil.isAscii(text)) {
953 charset = MimeUtility.getDefaultMIMECharset();
954 }
955 else {
956 charset = "us-ascii";
957 }
958 }
959 setContent(text, "text/" + subtype + "; charset=" + MimeUtility.quote(charset, HeaderTokenizer.MIME));
960 }
961
962 public void setContent(Multipart part) throws MessagingException {
963 setDataHandler(new DataHandler(part, part.getContentType()));
964 part.setParent(this);
965 }
966
967 public Message reply(boolean replyToAll) throws MessagingException {
968
969 MimeMessage reply = createMimeMessage(session);
970
971
972 String newSubject = getSubject();
973 if (newSubject != null) {
974
975
976 if (!newSubject.regionMatches(true, 0, "Re: ", 0, 4)) {
977 newSubject = "Re: " + newSubject;
978 }
979 reply.setSubject(newSubject);
980 }
981
982 Address[] toRecipients = getReplyTo();
983
984
985 reply.setRecipients(Message.RecipientType.TO, getReplyTo());
986
987
988 if (replyToAll) {
989
990
991 HashMap masterList = new HashMap();
992
993
994 InternetAddress localMail = InternetAddress.getLocalAddress(session);
995 if (localMail != null) {
996 masterList.put(localMail.getAddress(), localMail);
997 }
998
999 String alternates = session.getProperty(MAIL_ALTERNATES);
1000 if (alternates != null) {
1001
1002 Address[] alternateList = InternetAddress.parse(alternates, false);
1003 mergeAddressList(masterList, alternateList);
1004 }
1005
1006
1007
1008
1009
1010
1011 Address[] toList = pruneAddresses(masterList, getRecipients(Message.RecipientType.TO));
1012 if (toList.length != 0) {
1013
1014
1015
1016 if (SessionUtil.getBooleanProperty(session, MAIL_REPLYALLCC, false)) {
1017 reply.addRecipients(Message.RecipientType.CC, toList);
1018 }
1019 else {
1020 reply.addRecipients(Message.RecipientType.TO, toList);
1021 }
1022 }
1023
1024 toList = pruneAddresses(masterList, getRecipients(Message.RecipientType.CC));
1025 if (toList.length != 0) {
1026 reply.addRecipients(Message.RecipientType.CC, toList);
1027 }
1028
1029
1030
1031 toList = getRecipients(RecipientType.NEWSGROUPS);
1032 if (toList != null && toList.length != 0) {
1033 reply.addRecipients(RecipientType.NEWSGROUPS, toList);
1034 }
1035 }
1036
1037
1038
1039
1040
1041 setFlags(new Flags(Flags.Flag.ANSWERED), true);
1042
1043 return reply;
1044 }
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 private void mergeAddressList(Map master, Address[] list) {
1055
1056 if (list == null) {
1057 return;
1058 }
1059 for (int i = 0; i < list.length; i++) {
1060 InternetAddress address = (InternetAddress)list[i];
1061
1062
1063 if (!master.containsKey(address.getAddress())) {
1064 master.put(address.getAddress(), address);
1065 }
1066 }
1067 }
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080 private Address[] pruneAddresses(Map master, Address[] list) {
1081
1082 if (list == null) {
1083 return new Address[0];
1084 }
1085
1086
1087 ArrayList prunedList = new ArrayList(list.length);
1088 for (int i = 0; i < list.length; i++) {
1089 InternetAddress address = (InternetAddress)list[i];
1090
1091
1092
1093 if (!master.containsKey(address.getAddress())) {
1094 master.put(address.getAddress(), address);
1095 prunedList.add(address);
1096 }
1097 }
1098
1099 return (Address[])prunedList.toArray(new Address[0]);
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111 public void writeTo(OutputStream out) throws MessagingException, IOException {
1112 writeTo(out, null);
1113 }
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127 public void writeTo(OutputStream out, String[] ignoreHeaders) throws MessagingException, IOException {
1128
1129 if (!saved) {
1130 saveChanges();
1131 }
1132
1133
1134 headers.writeTo(out, ignoreHeaders);
1135
1136 out.write('\r');
1137 out.write('\n');
1138
1139
1140
1141 if (modified) {
1142 dh.writeTo(MimeUtility.encode(out, getEncoding()));
1143 } else {
1144
1145 if (content != null) {
1146 out.write(content);
1147 }
1148 else {
1149
1150
1151 InputStream in = getContentStream();
1152
1153 byte[] buffer = new byte[8192];
1154 int length = in.read(buffer);
1155
1156 while (length > 0) {
1157 out.write(buffer, 0, length);
1158 length = in.read(buffer);
1159 }
1160 in.close();
1161 }
1162 }
1163
1164
1165 out.flush();
1166 }
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179 public String[] getHeader(String name) throws MessagingException {
1180 return headers.getHeader(name);
1181 }
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 public String getHeader(String name, String delimiter) throws MessagingException {
1196 return headers.getHeader(name, delimiter);
1197 }
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 public void setHeader(String name, String value) throws MessagingException {
1208 headers.setHeader(name, value);
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221 private void setOrRemoveHeader(String name, String value) throws MessagingException {
1222 if (value == null) {
1223 headers.removeHeader(name);
1224 }
1225 else {
1226 headers.setHeader(name, value);
1227 }
1228 }
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239 public void addHeader(String name, String value) throws MessagingException {
1240 headers.addHeader(name, value);
1241 }
1242
1243
1244
1245
1246
1247
1248
1249
1250 public void removeHeader(String name) throws MessagingException {
1251 headers.removeHeader(name);
1252 }
1253
1254
1255
1256
1257
1258
1259
1260 public Enumeration getAllHeaders() throws MessagingException {
1261 return headers.getAllHeaders();
1262 }
1263
1264 public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
1265 return headers.getMatchingHeaders(names);
1266 }
1267
1268 public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
1269 return headers.getNonMatchingHeaders(names);
1270 }
1271
1272 public void addHeaderLine(String line) throws MessagingException {
1273 headers.addHeaderLine(line);
1274 }
1275
1276 public Enumeration getAllHeaderLines() throws MessagingException {
1277 return headers.getAllHeaderLines();
1278 }
1279
1280 public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
1281 return headers.getMatchingHeaderLines(names);
1282 }
1283
1284 public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
1285 return headers.getNonMatchingHeaderLines(names);
1286 }
1287
1288
1289
1290
1291
1292
1293
1294
1295 public synchronized Flags getFlags() throws MessagingException {
1296 return (Flags) flags.clone();
1297 }
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308 public synchronized boolean isSet(Flags.Flag flag) throws MessagingException {
1309 return flags.contains(flag);
1310 }
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320 public synchronized void setFlags(Flags flag, boolean set) throws MessagingException {
1321 if (set) {
1322 flags.add(flag);
1323 }
1324 else {
1325 flags.remove(flag);
1326 }
1327 }
1328
1329
1330
1331
1332
1333
1334
1335
1336 public void saveChanges() throws MessagingException {
1337
1338 modified = true;
1339 saved = true;
1340
1341 updateHeaders();
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351 protected void updateHeaders() throws MessagingException {
1352
1353
1354 setHeader("MIME-Version", "1.0");
1355
1356 DataHandler handler = getDataHandler();
1357
1358 try {
1359
1360 String type = dh.getContentType();
1361
1362 ContentType content = new ContentType(type);
1363
1364
1365 if (content.match("multipart/*")) {
1366
1367 try {
1368 MimeMultipart part = (MimeMultipart)handler.getContent();
1369 part.updateHeaders();
1370 } catch (ClassCastException e) {
1371 throw new MessagingException("Message content is not MimeMultipart", e);
1372 }
1373 }
1374 else if (!content.match("message/rfc822")) {
1375
1376
1377 if (getSingleHeader("Content-Transfer-Encoding") == null) {
1378 setHeader("Content-Transfer-Encoding", MimeUtility.getEncoding(handler));
1379 }
1380
1381
1382 if (getSingleHeader("Content-Type") == null) {
1383 if (SessionUtil.getBooleanProperty(session, "MIME_MAIL_SETDEFAULTTEXTCHARSET", true)) {
1384
1385 if (content.match("text/*")) {
1386
1387
1388 if (content.getParameter("charset") == null) {
1389
1390 String encoding = getEncoding();
1391
1392
1393 if (encoding != null && encoding.equalsIgnoreCase("7bit")) {
1394 content.setParameter("charset", "us-ascii");
1395 }
1396 else {
1397
1398 content.setParameter("charset", MimeUtility.getDefaultMIMECharset());
1399 }
1400 }
1401 }
1402 }
1403 }
1404 }
1405
1406
1407 if (getSingleHeader("Content-Type") == null) {
1408
1409
1410 String disp = getSingleHeader("Content-Disposition");
1411 if (disp != null) {
1412
1413 ContentDisposition disposition = new ContentDisposition(disp);
1414
1415 String filename = disposition.getParameter("filename");
1416
1417 if (filename != null) {
1418 content.setParameter("name", filename);
1419 }
1420 }
1421
1422 setHeader("Content-Type", content.toString());
1423 }
1424
1425
1426 updateMessageID();
1427
1428 } catch (IOException e) {
1429 throw new MessagingException("Error updating message headers", e);
1430 }
1431 }
1432
1433
1434 protected InternetHeaders createInternetHeaders(InputStream in) throws MessagingException {
1435
1436 return new InternetHeaders(in);
1437 }
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447 private Address[] getHeaderAsNewsAddresses(String header) throws MessagingException {
1448
1449
1450 String mergedHeader = getHeader(header, ",");
1451 if (mergedHeader != null) {
1452 return NewsAddress.parse(mergedHeader);
1453 }
1454 return null;
1455 }
1456
1457 private Address[] getHeaderAsInternetAddresses(String header, boolean strict) throws MessagingException {
1458
1459
1460 String mergedHeader = getHeader(header, ",");
1461
1462 if (mergedHeader != null) {
1463 return InternetAddress.parseHeader(mergedHeader, strict);
1464 }
1465 return null;
1466 }
1467
1468
1469
1470
1471
1472
1473
1474
1475 private boolean isStrictAddressing() {
1476 return SessionUtil.getBooleanProperty(session, MIME_ADDRESS_STRICT, true);
1477 }
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487 private void setHeader(String header, Address address) throws MessagingException {
1488 if (address == null) {
1489 removeHeader(header);
1490 }
1491 else {
1492 setHeader(header, address.toString());
1493 }
1494 }
1495
1496
1497
1498
1499
1500
1501
1502
1503 private void setHeader(String header, Address[] addresses) {
1504 if (addresses == null) {
1505 headers.removeHeader(header);
1506 }
1507 else {
1508 headers.setHeader(header, addresses);
1509 }
1510 }
1511
1512 private void addHeader(String header, Address[] addresses) throws MessagingException {
1513 headers.addHeader(header, InternetAddress.toString(addresses));
1514 }
1515
1516 private String getHeaderForRecipientType(Message.RecipientType type) throws MessagingException {
1517 if (RecipientType.TO == type) {
1518 return "To";
1519 } else if (RecipientType.CC == type) {
1520 return "Cc";
1521 } else if (RecipientType.BCC == type) {
1522 return "Bcc";
1523 } else if (RecipientType.NEWSGROUPS == type) {
1524 return "Newsgroups";
1525 } else {
1526 throw new MessagingException("Unsupported recipient type: " + type.toString());
1527 }
1528 }
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540 private String getSingleHeader(String name) throws MessagingException {
1541 String[] values = getHeader(name);
1542 if (values == null || values.length == 0) {
1543 return null;
1544 } else {
1545 return values[0];
1546 }
1547 }
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562 protected void updateMessageID() throws MessagingException {
1563 StringBuffer id = new StringBuffer();
1564
1565 id.append('<');
1566 id.append(new Object().hashCode());
1567 id.append('.');
1568 id.append(messageID++);
1569 id.append(System.currentTimeMillis());
1570 id.append('.');
1571 id.append("JavaMail.");
1572
1573
1574
1575 InternetAddress localAddress = InternetAddress.getLocalAddress(session);
1576 if (localAddress != null) {
1577 id.append(localAddress.getAddress());
1578 }
1579 else {
1580 id.append("javamailuser@localhost");
1581 }
1582 id.append('>');
1583
1584 setHeader("Message-ID", id.toString());
1585 }
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599 protected MimeMessage createMimeMessage(Session session) throws javax.mail.MessagingException {
1600 return new MimeMessage(session);
1601 }
1602
1603 }