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.transport.mailets;
23
24 import java.io.PrintWriter;
25 import java.io.StringWriter;
26
27 import java.util.Collection;
28 import java.util.Date;
29 import java.util.Enumeration;
30 import java.util.HashSet;
31 import java.util.Iterator;
32 import java.util.Locale;
33 import java.util.ArrayList;
34
35
36 import javax.mail.Message;
37 import javax.mail.MessagingException;
38 import javax.mail.internet.ParseException;
39 import javax.mail.Session;
40 import javax.mail.internet.InternetAddress;
41 import javax.mail.internet.MimeBodyPart;
42 import javax.mail.internet.MimeMessage;
43 import javax.mail.internet.MimeMultipart;
44
45 import org.apache.mailet.base.RFC2822Headers;
46 import org.apache.mailet.base.RFC822DateFormat;
47 import org.apache.james.Constants;
48 import org.apache.james.core.MailImpl;
49 import org.apache.james.core.MimeMessageUtil;
50
51 import org.apache.mailet.base.GenericMailet;
52 import org.apache.mailet.Mail;
53 import org.apache.mailet.MailAddress;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 public abstract class AbstractRedirect extends GenericMailet {
137
138
139
140
141
142
143 protected String[] getAllowedInitParameters() {
144 return null;
145 }
146
147
148
149
150 protected boolean isDebug = false;
151
152
153
154
155 protected boolean isStatic = false;
156
157 private static class AddressMarker {
158 public static MailAddress SENDER;
159 public static MailAddress REVERSE_PATH;
160 public static MailAddress FROM;
161 public static MailAddress REPLY_TO;
162 public static MailAddress TO;
163 public static MailAddress RECIPIENTS;
164 public static MailAddress DELETE;
165 public static MailAddress UNALTERED;
166 public static MailAddress NULL;
167
168 static {
169 try {
170 SENDER = new MailAddress("sender","address.marker");
171 REVERSE_PATH = new MailAddress("reverse.path","address.marker");
172 FROM = new MailAddress("from","address.marker");
173 REPLY_TO = new MailAddress("reply.to","address.marker");
174 TO = new MailAddress("to","address.marker");
175 RECIPIENTS = new MailAddress("recipients","address.marker");
176 DELETE = new MailAddress("delete","address.marker");
177 UNALTERED = new MailAddress("unaltered","address.marker");
178 NULL = new MailAddress("null","address.marker");
179
180 } catch (Exception _) {}
181 }
182 }
183
184
185
186
187
188
189 protected static class SpecialAddress {
190 public static final MailAddress SENDER = AddressMarker.SENDER;
191 public static final MailAddress REVERSE_PATH = AddressMarker.REVERSE_PATH;
192 public static final MailAddress FROM = AddressMarker.FROM;
193 public static final MailAddress REPLY_TO = AddressMarker.REPLY_TO;
194 public static final MailAddress TO = AddressMarker.TO;
195 public static final MailAddress RECIPIENTS = AddressMarker.RECIPIENTS;
196 public static final MailAddress DELETE = AddressMarker.DELETE;
197 public static final MailAddress UNALTERED = AddressMarker.UNALTERED;
198 public static final MailAddress NULL = AddressMarker.NULL;
199 }
200
201
202
203
204 protected static final int UNALTERED = 0;
205
206 protected static final int HEADS = 1;
207
208 protected static final int BODY = 2;
209
210 protected static final int ALL = 3;
211
212 protected static final int NONE = 4;
213
214 protected static final int MESSAGE = 5;
215
216 private boolean passThrough = false;
217 private boolean fakeDomainCheck = true;
218 private int attachmentType = NONE;
219 private int inLineType = BODY;
220 private String messageText;
221 private Collection recipients;
222 private MailAddress replyTo;
223 private MailAddress reversePath;
224 private MailAddress sender;
225 private String subject;
226 private String subjectPrefix;
227 private InternetAddress[] apparentlyTo;
228 private boolean attachError = false;
229 private boolean isReply = false;
230
231 private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 protected boolean isStatic() {
253 return true;
254 }
255
256
257
258
259
260
261
262
263 protected boolean getPassThrough() throws MessagingException {
264 return new Boolean(getInitParameter("passThrough")).booleanValue();
265 }
266
267
268
269
270
271
272
273
274 protected boolean getPassThrough(Mail originalMail) throws MessagingException {
275 return (isStatic()) ? this.passThrough : getPassThrough();
276 }
277
278
279
280
281
282
283
284
285 protected boolean getFakeDomainCheck() throws MessagingException {
286 return new Boolean(getInitParameter("fakeDomainCheck")).booleanValue();
287 }
288
289
290
291
292
293
294
295
296 protected boolean getFakeDomainCheck(Mail originalMail) throws MessagingException {
297 return (isStatic()) ? this.fakeDomainCheck : getFakeDomainCheck();
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315 protected int getInLineType() throws MessagingException {
316 return getTypeCode(getInitParameter("inline","unaltered"));
317 }
318
319
320
321
322
323
324
325
326 protected int getInLineType(Mail originalMail) throws MessagingException {
327 return (isStatic()) ? this.inLineType : getInLineType();
328 }
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 protected int getAttachmentType() throws MessagingException {
345 return getTypeCode(getInitParameter("attachment","none"));
346 }
347
348
349
350
351
352
353
354
355 protected int getAttachmentType(Mail originalMail) throws MessagingException {
356 return (isStatic()) ? this.attachmentType : getAttachmentType();
357 }
358
359
360
361
362
363
364
365
366
367 protected String getMessage() throws MessagingException {
368 return getInitParameter("message","");
369 }
370
371
372
373
374
375
376
377
378 protected String getMessage(Mail originalMail) throws MessagingException {
379 return (isStatic()) ? this.messageText : getMessage();
380 }
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398 protected Collection getRecipients() throws MessagingException {
399 Collection newRecipients = new HashSet();
400 String addressList = getInitParameter("recipients");
401
402
403 if (addressList == null) {
404 return null;
405 }
406
407 try {
408 InternetAddress[] iaarray = InternetAddress.parse(addressList, false);
409 for (int i = 0; i < iaarray.length; i++) {
410 String addressString = iaarray[i].getAddress();
411 MailAddress specialAddress = getSpecialAddress(addressString,
412 new String[] {"postmaster", "sender", "from", "replyTo", "reversePath", "unaltered", "recipients", "to", "null"});
413 if (specialAddress != null) {
414 newRecipients.add(specialAddress);
415 } else {
416 newRecipients.add(new MailAddress(iaarray[i]));
417 }
418 }
419 } catch (Exception e) {
420 throw new MessagingException("Exception thrown in getRecipients() parsing: " + addressList, e);
421 }
422 if (newRecipients.size() == 0) {
423 throw new MessagingException("Failed to initialize \"recipients\" list; empty <recipients> init parameter found.");
424 }
425
426 return newRecipients;
427 }
428
429
430
431
432
433
434
435
436 protected Collection getRecipients(Mail originalMail) throws MessagingException {
437 Collection recipients = (isStatic()) ? this.recipients : getRecipients();
438 if (recipients != null) {
439 if (recipients.size() == 1 && (recipients.contains(SpecialAddress.UNALTERED) || recipients.contains(SpecialAddress.RECIPIENTS))) {
440 recipients = null;
441 } else {
442 recipients = replaceMailAddresses(originalMail, recipients);
443 }
444 }
445 return recipients;
446 }
447
448
449
450
451
452
453 protected void setRecipients(Mail newMail, Collection recipients, Mail originalMail) throws MessagingException {
454 if (recipients != null) {
455 newMail.setRecipients(recipients);
456 if (isDebug) {
457 log("recipients set to: " + arrayToString(recipients.toArray()));
458 }
459 }
460 }
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478 protected InternetAddress[] getTo() throws MessagingException {
479 InternetAddress[] iaarray = null;
480 String addressList = getInitParameter("to");
481
482
483 if (addressList == null) {
484 return null;
485 }
486
487 try {
488 iaarray = InternetAddress.parse(addressList, false);
489 for(int i = 0; i < iaarray.length; ++i) {
490 String addressString = iaarray[i].getAddress();
491 MailAddress specialAddress = getSpecialAddress(addressString,
492 new String[] {"postmaster", "sender", "from", "replyTo", "reversePath", "unaltered", "recipients", "to", "null"});
493 if (specialAddress != null) {
494 iaarray[i] = specialAddress.toInternetAddress();
495 }
496 }
497 } catch (Exception e) {
498 throw new MessagingException("Exception thrown in getTo() parsing: " + addressList, e);
499 }
500 if (iaarray.length == 0) {
501 throw new MessagingException("Failed to initialize \"to\" list; empty <to> init parameter found.");
502 }
503
504 return iaarray;
505 }
506
507
508
509
510
511
512
513
514
515
516 protected InternetAddress[] getTo(Mail originalMail) throws MessagingException {
517 InternetAddress[] apparentlyTo = (isStatic()) ? this.apparentlyTo : getTo();
518 if (apparentlyTo != null) {
519 if ( apparentlyTo.length == 1
520 && ( apparentlyTo[0].equals(SpecialAddress.UNALTERED.toInternetAddress())
521 || apparentlyTo[0].equals(SpecialAddress.TO.toInternetAddress())
522 )) {
523 apparentlyTo = null;
524 } else {
525 Collection toList = new ArrayList(apparentlyTo.length);
526 for (int i = 0; i < apparentlyTo.length; i++) {
527 toList.add(apparentlyTo[i]);
528 }
529
530
531
532 apparentlyTo = (InternetAddress[]) replaceInternetAddresses(originalMail, toList).toArray(new InternetAddress[0]);
533 }
534 }
535
536 return apparentlyTo;
537 }
538
539
540
541
542
543
544 protected void setTo(Mail newMail, InternetAddress[] to, Mail originalMail) throws MessagingException {
545 if (to != null) {
546 newMail.getMessage().setRecipients(Message.RecipientType.TO, to);
547 if (isDebug) {
548 log("apparentlyTo set to: " + arrayToString(to));
549 }
550 }
551 }
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566 protected MailAddress getReplyTo() throws MessagingException {
567 String addressString = getInitParameter("replyTo",getInitParameter("replyto"));
568
569 if(addressString != null) {
570 MailAddress specialAddress = getSpecialAddress(addressString,
571 new String[] {"postmaster", "sender", "null", "unaltered"});
572 if (specialAddress != null) {
573 return specialAddress;
574 }
575
576 try {
577 return new MailAddress(addressString);
578 } catch(Exception e) {
579 throw new MessagingException("Exception thrown in getReplyTo() parsing: " + addressString, e);
580 }
581 }
582
583 return null;
584 }
585
586
587
588
589
590
591
592
593
594
595 protected MailAddress getReplyTo(Mail originalMail) throws MessagingException {
596 MailAddress replyTo = (isStatic()) ? this.replyTo : getReplyTo();
597 if (replyTo != null) {
598 if (replyTo == SpecialAddress.UNALTERED) {
599 replyTo = null;
600 } else if (replyTo == SpecialAddress.SENDER) {
601 replyTo = originalMail.getSender();
602 }
603 }
604 return replyTo;
605 }
606
607
608
609
610
611
612
613 protected void setReplyTo(Mail newMail, MailAddress replyTo, Mail originalMail) throws MessagingException {
614 if(replyTo != null) {
615 InternetAddress[] iart = null;
616 if (replyTo != SpecialAddress.NULL) {
617 iart = new InternetAddress[1];
618 iart[0] = replyTo.toInternetAddress();
619 }
620
621
622 newMail.getMessage().setReplyTo(iart);
623
624 if (isDebug) {
625 log("replyTo set to: " + replyTo);
626 }
627 }
628 }
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643 protected MailAddress getReversePath() throws MessagingException {
644 String addressString = getInitParameter("reversePath");
645 if(addressString != null) {
646 MailAddress specialAddress = getSpecialAddress(addressString,
647 new String[] {"postmaster", "sender", "null", "unaltered"});
648 if (specialAddress != null) {
649 return specialAddress;
650 }
651
652 try {
653 return new MailAddress(addressString);
654 } catch(Exception e) {
655 throw new MessagingException("Exception thrown in getReversePath() parsing: " + addressString, e);
656 }
657 }
658
659 return null;
660 }
661
662
663
664
665
666
667
668
669
670
671
672
673
674 protected MailAddress getReversePath(Mail originalMail) throws MessagingException {
675 MailAddress reversePath = (isStatic()) ? this.reversePath : getReversePath();
676 if (reversePath != null) {
677 if (reversePath == SpecialAddress.UNALTERED || reversePath == SpecialAddress.REVERSE_PATH) {
678 reversePath = null;
679 }
680 else if (reversePath == SpecialAddress.SENDER) {
681 reversePath = null;
682 }
683 }
684 return reversePath;
685 }
686
687
688
689
690
691
692
693 protected void setReversePath(MailImpl newMail, MailAddress reversePath, Mail originalMail) throws MessagingException {
694 if(reversePath != null) {
695 if (reversePath == SpecialAddress.NULL) {
696 reversePath = null;
697 }
698 newMail.setSender(reversePath);
699 if (isDebug) {
700 log("reversePath set to: " + reversePath);
701 }
702 }
703 }
704
705
706
707
708
709
710
711
712
713
714
715
716
717 protected MailAddress getSender() throws MessagingException {
718 String addressString = getInitParameter("sender");
719 if(addressString != null) {
720 MailAddress specialAddress = getSpecialAddress(addressString,
721 new String[] {"postmaster", "sender", "unaltered"});
722 if (specialAddress != null) {
723 return specialAddress;
724 }
725
726 try {
727 return new MailAddress(addressString);
728 } catch(Exception e) {
729 throw new MessagingException("Exception thrown in getSender() parsing: " + addressString, e);
730 }
731 }
732
733 return null;
734 }
735
736
737
738
739
740
741
742
743
744
745 protected MailAddress getSender(Mail originalMail) throws MessagingException {
746 MailAddress sender = (isStatic()) ? this.sender : getSender();
747 if (sender != null) {
748 if (sender == SpecialAddress.UNALTERED || sender == SpecialAddress.SENDER) {
749 sender = null;
750 }
751 }
752 return sender;
753 }
754
755
756
757
758
759
760 protected void setSender(Mail newMail, MailAddress sender, Mail originalMail) throws MessagingException {
761 if (sender != null) {
762 newMail.getMessage().setFrom(sender.toInternetAddress());
763
764 if (isDebug) {
765 log("sender set to: " + sender);
766 }
767 }
768 }
769
770
771
772
773
774
775
776
777 protected String getSubject() throws MessagingException {
778 return getInitParameter("subject");
779 }
780
781
782
783
784
785
786
787
788 protected String getSubject(Mail originalMail) throws MessagingException {
789 return (isStatic()) ? this.subject : getSubject();
790 }
791
792
793
794
795
796
797
798
799 protected String getSubjectPrefix() throws MessagingException {
800 return getInitParameter("prefix");
801 }
802
803
804
805
806
807
808
809
810 protected String getSubjectPrefix(Mail originalMail) throws MessagingException {
811 return (isStatic()) ? this.subjectPrefix : getSubjectPrefix();
812 }
813
814
815
816
817
818
819 protected void setSubjectPrefix(Mail newMail, String subjectPrefix, Mail originalMail) throws MessagingException {
820 String subject = getSubject(originalMail);
821 if ((subjectPrefix != null && subjectPrefix.length() > 0) || subject != null) {
822 if (subject == null) {
823 subject = originalMail.getMessage().getSubject();
824 } else {
825
826 if (isDebug) {
827 log("subject set to: " + subject);
828 }
829 }
830
831 if (subject == null) {
832 subject = "";
833 }
834
835 if (subjectPrefix != null) {
836 subject = subjectPrefix + subject;
837
838 if (isDebug) {
839 log("subjectPrefix set to: " + subjectPrefix);
840 }
841 }
842
843 changeSubject(newMail.getMessage(), subject);
844 }
845 }
846
847
848
849
850
851
852
853
854
855 protected boolean attachError() throws MessagingException {
856 return new Boolean(getInitParameter("attachError")).booleanValue();
857 }
858
859
860
861
862
863
864
865
866 protected boolean attachError(Mail originalMail) throws MessagingException {
867 return (isStatic()) ? this.attachError : attachError();
868 }
869
870
871
872
873
874
875
876
877
878
879 protected boolean isReply() throws MessagingException {
880 return new Boolean(getInitParameter("isReply")).booleanValue();
881 }
882
883
884
885
886
887
888
889
890 protected boolean isReply(Mail originalMail) throws MessagingException {
891 return (isStatic()) ? this.isReply : isReply();
892 }
893
894
895
896
897
898 protected void setIsReply(Mail newMail, boolean isReply, Mail originalMail) throws MessagingException {
899 if (isReply) {
900 String messageId = originalMail.getMessage().getMessageID();
901 if (messageId != null) {
902 newMail.getMessage().setHeader(RFC2822Headers.IN_REPLY_TO, messageId);
903 if (isDebug) {
904 log("IN_REPLY_TO set to: " + messageId);
905 }
906 }
907 }
908 }
909
910
911
912
913
914
915
916
917
918
919 public void init() throws MessagingException {
920 isDebug = new Boolean(getInitParameter("debug","false")).booleanValue();
921
922 isStatic = new Boolean(getInitParameter("static","false")).booleanValue();
923
924 if (isDebug) {
925 log("Initializing");
926 }
927
928
929 checkInitParameters(getAllowedInitParameters());
930
931 if(isStatic()) {
932 passThrough = getPassThrough();
933 fakeDomainCheck = getFakeDomainCheck();
934 attachmentType = getAttachmentType();
935 inLineType = getInLineType();
936 messageText = getMessage();
937 recipients = getRecipients();
938 replyTo = getReplyTo();
939 reversePath = getReversePath();
940 sender = getSender();
941 subject = getSubject();
942 subjectPrefix = getSubjectPrefix();
943 apparentlyTo = getTo();
944 attachError = attachError();
945 isReply = isReply();
946 if (isDebug) {
947 StringBuffer logBuffer =
948 new StringBuffer(1024)
949 .append("static")
950 .append(", passThrough=").append(passThrough)
951 .append(", fakeDomainCheck=").append(fakeDomainCheck)
952 .append(", sender=").append(sender)
953 .append(", replyTo=").append(replyTo)
954 .append(", reversePath=").append(reversePath)
955 .append(", message=").append(messageText)
956 .append(", recipients=").append(arrayToString(recipients == null ? null : recipients.toArray()))
957 .append(", subject=").append(subject)
958 .append(", subjectPrefix=").append(subjectPrefix)
959 .append(", apparentlyTo=").append(arrayToString(apparentlyTo))
960 .append(", attachError=").append(attachError)
961 .append(", isReply=").append(isReply)
962 .append(", attachmentType=").append(attachmentType)
963 .append(", inLineType=").append(inLineType)
964 .append(" ");
965 log(logBuffer.toString());
966 }
967 }
968 }
969
970
971
972
973
974
975
976 public void service(Mail originalMail) throws MessagingException {
977
978 boolean keepMessageId = false;
979
980
981 MailImpl newMail = new MailImpl(originalMail);
982 try {
983
984
985
986 newMail.setRemoteAddr(getMailetContext().getAttribute(Constants.HOSTADDRESS).toString());
987 newMail.setRemoteHost(getMailetContext().getAttribute(Constants.HOSTNAME).toString());
988
989 if (isDebug) {
990 log("New mail - sender: " + newMail.getSender()
991 + ", recipients: " + arrayToString(newMail.getRecipients().toArray())
992 + ", name: " + newMail.getName()
993 + ", remoteHost: " + newMail.getRemoteHost()
994 + ", remoteAddr: " + newMail.getRemoteAddr()
995 + ", state: " + newMail.getState()
996 + ", lastUpdated: " + newMail.getLastUpdated()
997 + ", errorMessage: " + newMail.getErrorMessage());
998 }
999
1000
1001 if(getInLineType(originalMail) != UNALTERED) {
1002 if (isDebug) {
1003 log("Alter message");
1004 }
1005 newMail.setMessage(new MimeMessage(Session.getDefaultInstance(System.getProperties(),
1006 null)));
1007
1008
1009 buildAlteredMessage(newMail, originalMail);
1010
1011 } else {
1012
1013 if (getPassThrough(originalMail)) {
1014 newMail.setMessage(new MimeMessage(originalMail.getMessage()) {
1015 protected void updateHeaders() throws MessagingException {
1016 if (getMessageID() == null) super.updateHeaders();
1017 else {
1018 modified = false;
1019 }
1020 }
1021 });
1022 }
1023 if (isDebug) {
1024 log("Message resent unaltered.");
1025 }
1026 keepMessageId = true;
1027 }
1028
1029
1030
1031 setRecipients(newMail, getRecipients(originalMail), originalMail);
1032
1033 setTo(newMail, getTo(originalMail), originalMail);
1034
1035 setSubjectPrefix(newMail, getSubjectPrefix(originalMail), originalMail);
1036
1037 if(newMail.getMessage().getHeader(RFC2822Headers.DATE) == null) {
1038 newMail.getMessage().setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new Date()));
1039 }
1040
1041 setReplyTo(newMail, getReplyTo(originalMail), originalMail);
1042
1043 setReversePath(newMail, getReversePath(originalMail), originalMail);
1044
1045 setSender(newMail, getSender(originalMail), originalMail);
1046
1047 setIsReply(newMail, isReply(originalMail), originalMail);
1048
1049 newMail.getMessage().saveChanges();
1050
1051 if (keepMessageId) {
1052 setMessageId(newMail, originalMail);
1053 }
1054
1055 if (senderDomainIsValid(newMail)) {
1056
1057 getMailetContext().sendMail(newMail);
1058 } else {
1059 StringBuffer logBuffer = new StringBuffer(256)
1060 .append(getMailetName())
1061 .append(" mailet cannot forward ")
1062 .append(originalMail.getName())
1063 .append(". Invalid sender domain for ")
1064 .append(newMail.getSender())
1065 .append(". Consider using the Resend mailet ")
1066 .append("using a different sender.");
1067 throw new MessagingException(logBuffer.toString());
1068 }
1069
1070 } finally {
1071 newMail.dispose();
1072 }
1073
1074 if(!getPassThrough(originalMail)) {
1075 originalMail.setState(Mail.GHOST);
1076 }
1077 }
1078
1079
1080
1081
1082
1083
1084
1085
1086 protected int getTypeCode(String param) {
1087 param = param.toLowerCase(Locale.US);
1088 if(param.compareTo("unaltered") == 0) {
1089 return UNALTERED;
1090 }
1091 if(param.compareTo("heads") == 0) {
1092 return HEADS;
1093 }
1094 if(param.compareTo("body") == 0) {
1095 return BODY;
1096 }
1097 if(param.compareTo("all") == 0) {
1098 return ALL;
1099 }
1100 if(param.compareTo("none") == 0) {
1101 return NONE;
1102 }
1103 if(param.compareTo("message") == 0) {
1104 return MESSAGE;
1105 }
1106 return NONE;
1107 }
1108
1109
1110
1111
1112
1113 protected String getMessageHeaders(MimeMessage message) throws MessagingException {
1114 Enumeration heads = message.getAllHeaderLines();
1115 StringBuffer headBuffer = new StringBuffer(1024);
1116 while(heads.hasMoreElements()) {
1117 headBuffer.append(heads.nextElement().toString()).append("\r\n");
1118 }
1119 return headBuffer.toString();
1120 }
1121
1122
1123
1124
1125
1126 private String getMessageBody(MimeMessage message) throws Exception {
1127 java.io.ByteArrayOutputStream bodyOs = new java.io.ByteArrayOutputStream();
1128 MimeMessageUtil.writeMessageBodyTo(message,bodyOs);
1129 return bodyOs.toString();
1130 }
1131
1132
1133
1134
1135
1136
1137
1138 protected void buildAlteredMessage(Mail newMail, Mail originalMail) throws MessagingException {
1139
1140 MimeMessage originalMessage = originalMail.getMessage();
1141 MimeMessage newMessage = newMail.getMessage();
1142
1143
1144 String[] relevantHeaderNames =
1145 {RFC2822Headers.DATE,
1146 RFC2822Headers.FROM,
1147 RFC2822Headers.REPLY_TO,
1148 RFC2822Headers.TO,
1149 RFC2822Headers.SUBJECT,
1150 RFC2822Headers.RETURN_PATH};
1151 Enumeration headerEnum = originalMessage.getMatchingHeaderLines(relevantHeaderNames);
1152 while (headerEnum.hasMoreElements()) {
1153 newMessage.addHeaderLine((String) headerEnum.nextElement());
1154 }
1155
1156 StringWriter sout = new StringWriter();
1157 PrintWriter out = new PrintWriter(sout, true);
1158 String head = getMessageHeaders(originalMessage);
1159 boolean all = false;
1160
1161 String messageText = getMessage(originalMail);
1162 if(messageText != null) {
1163 out.println(messageText);
1164 }
1165
1166 if (isDebug) {
1167 log("inline:" + getInLineType(originalMail));
1168 }
1169 switch(getInLineType(originalMail)) {
1170 case ALL:
1171 all = true;
1172 case HEADS:
1173 out.println("Message Headers:");
1174 out.println(head);
1175 if(!all) {
1176 break;
1177 }
1178 case BODY:
1179 out.println("Message:");
1180 try {
1181 out.println(getMessageBody(originalMessage));
1182 } catch(Exception e) {
1183 out.println("body unavailable");
1184 }
1185 break;
1186 default:
1187 case NONE:
1188 break;
1189 }
1190
1191 try {
1192
1193 MimeMultipart multipart = new MimeMultipart("mixed");
1194
1195
1196 MimeMultipart mpContent = new MimeMultipart("alternative");
1197 MimeBodyPart contentPartRoot = new MimeBodyPart();
1198 contentPartRoot.setContent(mpContent);
1199
1200 multipart.addBodyPart(contentPartRoot);
1201
1202 MimeBodyPart part = new MimeBodyPart();
1203 part.setText(sout.toString());
1204 part.setDisposition("inline");
1205 mpContent.addBodyPart(part);
1206 if (isDebug) {
1207 log("attachmentType:" + getAttachmentType(originalMail));
1208 }
1209 if(getAttachmentType(originalMail) != NONE) {
1210 part = new MimeBodyPart();
1211 switch(getAttachmentType(originalMail)) {
1212 case HEADS:
1213 part.setText(head);
1214 break;
1215 case BODY:
1216 try {
1217 part.setText(getMessageBody(originalMessage));
1218 } catch(Exception e) {
1219 part.setText("body unavailable");
1220 }
1221 break;
1222 case ALL:
1223 StringBuffer textBuffer =
1224 new StringBuffer(1024)
1225 .append(head)
1226 .append("\r\nMessage:\r\n")
1227 .append(getMessageBody(originalMessage));
1228 part.setText(textBuffer.toString());
1229 break;
1230 case MESSAGE:
1231 part.setContent(originalMessage, "message/rfc822");
1232 break;
1233 }
1234 if ((originalMessage.getSubject() != null) && (originalMessage.getSubject().trim().length() > 0)) {
1235 part.setFileName(originalMessage.getSubject().trim());
1236 } else {
1237 part.setFileName("No Subject");
1238 }
1239 part.setDisposition("Attachment");
1240 multipart.addBodyPart(part);
1241 }
1242
1243 if (attachError(originalMail) && originalMail.getErrorMessage() != null) {
1244 part = new MimeBodyPart();
1245 part.setContent(originalMail.getErrorMessage(), "text/plain");
1246 part.setHeader(RFC2822Headers.CONTENT_TYPE, "text/plain");
1247 part.setFileName("Reasons");
1248 part.setDisposition(javax.mail.Part.ATTACHMENT);
1249 multipart.addBodyPart(part);
1250 }
1251 newMail.getMessage().setContent(multipart);
1252 newMail.getMessage().setHeader(RFC2822Headers.CONTENT_TYPE, multipart.getContentType());
1253
1254 } catch (Exception ioe) {
1255 throw new MessagingException("Unable to create multipart body", ioe);
1256 }
1257 }
1258
1259
1260
1261
1262 private void setMessageId(Mail newMail, Mail originalMail) throws MessagingException {
1263 String messageId = originalMail.getMessage().getMessageID();
1264 if (messageId != null) {
1265 newMail.getMessage().setHeader(RFC2822Headers.MESSAGE_ID, messageId);
1266 if (isDebug) {
1267 log("MESSAGE_ID restored to: " + messageId);
1268 }
1269 }
1270 }
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282 protected final MailAddress getSpecialAddress(String addressString, String[] allowedSpecials) throws MessagingException {
1283 if (addressString == null) {
1284 return null;
1285 }
1286
1287 addressString = addressString.toLowerCase(Locale.US);
1288 addressString = addressString.trim();
1289
1290 MailAddress specialAddress = null;
1291
1292 if(addressString.compareTo("postmaster") == 0) {
1293 specialAddress = getMailetContext().getPostmaster();
1294 }
1295 if(addressString.compareTo("sender") == 0) {
1296 specialAddress = SpecialAddress.SENDER;
1297 }
1298 if(addressString.compareTo("reversepath") == 0) {
1299 specialAddress = SpecialAddress.REVERSE_PATH;
1300 }
1301 if(addressString.compareTo("from") == 0) {
1302 specialAddress = SpecialAddress.FROM;
1303 }
1304 if(addressString.compareTo("replyto") == 0) {
1305 specialAddress = SpecialAddress.REPLY_TO;
1306 }
1307 if(addressString.compareTo("to") == 0) {
1308 specialAddress = SpecialAddress.TO;
1309 }
1310 if(addressString.compareTo("recipients") == 0) {
1311 specialAddress = SpecialAddress.RECIPIENTS;
1312 }
1313 if(addressString.compareTo("delete") == 0) {
1314 specialAddress = SpecialAddress.DELETE;
1315 }
1316 if(addressString.compareTo("unaltered") == 0) {
1317 specialAddress = SpecialAddress.UNALTERED;
1318 }
1319 if(addressString.compareTo("null") == 0) {
1320 specialAddress = SpecialAddress.NULL;
1321 }
1322
1323
1324 if (specialAddress != null) {
1325
1326 boolean allowed = false;
1327 for (int i = 0; i < allowedSpecials.length; i++) {
1328 String allowedSpecial = allowedSpecials[i];
1329 allowedSpecial = allowedSpecial.toLowerCase(Locale.US);
1330 allowedSpecial = allowedSpecial.trim();
1331 if(addressString.compareTo(allowedSpecial) == 0) {
1332 allowed = true;
1333 break;
1334 }
1335 }
1336 if (!allowed) {
1337 throw new MessagingException("Special (\"magic\") address found not allowed: " + addressString +
1338 ", allowed values are \"" + arrayToString(allowedSpecials) + "\"");
1339 }
1340 }
1341
1342 return specialAddress;
1343 }
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361 protected final boolean senderDomainIsValid(Mail mail) throws MessagingException {
1362 if (getFakeDomainCheck(mail)) {
1363 return mail.getSender() == null || getMailetContext().getMailServers(mail.getSender().getHost()).size() != 0;
1364 } else return true;
1365 }
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 public static void changeSubject(MimeMessage message, String newValue)
1401 throws MessagingException
1402 {
1403 String rawSubject = message.getHeader(RFC2822Headers.SUBJECT, null);
1404 String mimeCharset = determineMailHeaderEncodingCharset(rawSubject);
1405 if (mimeCharset == null) {
1406
1407
1408 message.setSubject(newValue);
1409 return;
1410 } else {
1411 String javaCharset = javax.mail.internet.MimeUtility.javaCharset(mimeCharset);
1412 try {
1413 message.setSubject(newValue, javaCharset);
1414 } catch (MessagingException e) {
1415
1416
1417
1418
1419
1420 message.setSubject(newValue);
1421 }
1422 }
1423 }
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437 static private String determineMailHeaderEncodingCharset(String rawText)
1438 {
1439 if (rawText == null) return null;
1440 int iEncodingPrefix = rawText.indexOf("=?");
1441 if (iEncodingPrefix == -1) return null;
1442 int iCharsetBegin = iEncodingPrefix + 2;
1443 int iSecondQuestionMark = rawText.indexOf('?', iCharsetBegin);
1444 if (iSecondQuestionMark == -1) return null;
1445
1446 if (iSecondQuestionMark == iCharsetBegin) return null;
1447 int iThirdQuestionMark = rawText.indexOf('?', iSecondQuestionMark + 1);
1448 if (iThirdQuestionMark == -1) return null;
1449 if (-1 == rawText.indexOf("?=", iThirdQuestionMark + 1)) return null;
1450 String mimeCharset = rawText.substring(iCharsetBegin, iSecondQuestionMark);
1451 return mimeCharset;
1452 }
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468 protected Collection replaceMailAddresses(Mail mail, Collection list) {
1469 Collection newList = new HashSet(list.size());
1470 Iterator iterator = list.iterator();
1471 while (iterator.hasNext()) {
1472 MailAddress mailAddress = (MailAddress) iterator.next();
1473 if (!mailAddress.getHost().equalsIgnoreCase("address.marker")) {
1474 newList.add(mailAddress);
1475 } else if (mailAddress == SpecialAddress.SENDER || mailAddress == SpecialAddress.FROM) {
1476 MailAddress sender = mail.getSender();
1477 if (sender != null) {
1478 newList.add(sender);
1479 }
1480 } else if (mailAddress == SpecialAddress.REPLY_TO) {
1481 int parsedAddressCount = 0;
1482 try {
1483 InternetAddress[] replyToArray = (InternetAddress[]) mail.getMessage().getReplyTo();
1484 if (replyToArray != null) {
1485 for (int i = 0; i < replyToArray.length; i++) {
1486 try {
1487 newList.add(new MailAddress(replyToArray[i]));
1488 parsedAddressCount++;
1489 } catch (ParseException pe) {
1490 log("Unable to parse a \"REPLY_TO\" header address in the original message: " + replyToArray[i] + "; ignoring.");
1491 }
1492 }
1493 }
1494 } catch (MessagingException ae) {
1495 log("Unable to parse the \"REPLY_TO\" header in the original message; ignoring.");
1496 }
1497
1498 if (parsedAddressCount == 0) {
1499 MailAddress sender = mail.getSender();
1500 if (sender != null) {
1501 newList.add(sender);
1502 }
1503 }
1504 } else if (mailAddress == SpecialAddress.REVERSE_PATH) {
1505 MailAddress reversePath = mail.getSender();
1506 if (reversePath != null) {
1507 newList.add(reversePath);
1508 }
1509 } else if (mailAddress == SpecialAddress.RECIPIENTS || mailAddress == SpecialAddress.TO) {
1510 newList.addAll(mail.getRecipients());
1511 } else if (mailAddress == SpecialAddress.UNALTERED) {
1512 continue;
1513 } else if (mailAddress == SpecialAddress.NULL) {
1514 continue;
1515 } else {
1516 newList.add(mailAddress);
1517 }
1518 }
1519 return newList;
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537 protected Collection replaceInternetAddresses(Mail mail, Collection list) throws MessagingException {
1538 Collection newList = new HashSet(list.size());
1539 Iterator iterator = list.iterator();
1540 while (iterator.hasNext()) {
1541 InternetAddress internetAddress = (InternetAddress) iterator.next();
1542 MailAddress mailAddress = new MailAddress(internetAddress);
1543 if (!mailAddress.getHost().equalsIgnoreCase("address.marker")) {
1544 newList.add(internetAddress);
1545 } else if (internetAddress.equals(SpecialAddress.SENDER.toInternetAddress())) {
1546 MailAddress sender = mail.getSender();
1547 if (sender != null) {
1548 newList.add(sender.toInternetAddress());
1549 }
1550 } else if (internetAddress.equals(SpecialAddress.REVERSE_PATH.toInternetAddress())) {
1551 MailAddress reversePath = mail.getSender();
1552 if (reversePath != null) {
1553 newList.add(reversePath.toInternetAddress());
1554 }
1555 } else if (internetAddress.equals(SpecialAddress.FROM.toInternetAddress())) {
1556 try {
1557 InternetAddress[] fromArray = (InternetAddress[]) mail.getMessage().getFrom();
1558 if (fromArray != null) {
1559 for (int i = 0; i < fromArray.length; i++) {
1560 newList.add(fromArray[i]);
1561 }
1562 } else {
1563 MailAddress reversePath = mail.getSender();
1564 if (reversePath != null) {
1565 newList.add(reversePath.toInternetAddress());
1566 }
1567 }
1568 } catch (MessagingException me) {
1569 log("Unable to parse the \"FROM\" header in the original message; ignoring.");
1570 }
1571 } else if (internetAddress.equals(SpecialAddress.REPLY_TO.toInternetAddress())) {
1572 try {
1573 InternetAddress[] replyToArray = (InternetAddress[]) mail.getMessage().getReplyTo();
1574 if (replyToArray != null) {
1575 for (int i = 0; i < replyToArray.length; i++) {
1576 newList.add(replyToArray[i]);
1577 }
1578 } else {
1579 MailAddress reversePath = mail.getSender();
1580 if (reversePath != null) {
1581 newList.add(reversePath.toInternetAddress());
1582 }
1583 }
1584 } catch (MessagingException me) {
1585 log("Unable to parse the \"REPLY_TO\" header in the original message; ignoring.");
1586 }
1587 } else if (internetAddress.equals(SpecialAddress.TO.toInternetAddress())
1588 || internetAddress.equals(SpecialAddress.RECIPIENTS.toInternetAddress())) {
1589 try {
1590 String[] toHeaders = mail.getMessage().getHeader(RFC2822Headers.TO);
1591 if (toHeaders != null) {
1592 for (int i = 0; i < toHeaders.length; i++) {
1593 try {
1594 InternetAddress[] originalToInternetAddresses = InternetAddress.parse(toHeaders[i], false);
1595 for (int j = 0; j < originalToInternetAddresses.length; j++) {
1596 newList.add(originalToInternetAddresses[j]);
1597 }
1598 } catch (MessagingException ae) {
1599 log("Unable to parse a \"TO\" header address in the original message: " + toHeaders[i] + "; ignoring.");
1600 }
1601 }
1602 }
1603 } catch (MessagingException ae) {
1604 log("Unable to parse the \"TO\" header in the original message; ignoring.");
1605 }
1606 } else if (internetAddress.equals(SpecialAddress.UNALTERED.toInternetAddress())) {
1607 continue;
1608 } else if (internetAddress.equals(SpecialAddress.NULL.toInternetAddress())) {
1609 continue;
1610 } else {
1611 newList.add(internetAddress);
1612 }
1613 }
1614 return newList;
1615 }
1616
1617 }