noel 2003/06/01 22:40:28
Modified: src/java/org/apache/james/transport Tag: branch_2_1_fcs
LinearProcessor.java
src/java/org/apache/james/transport/mailets Tag:
branch_2_1_fcs Redirect.java
Log:
Improved performance when recipient matching is all or nothing.
Revision Changes Path
No revision
No revision
1.10.4.3 +13 -8
jakarta-james/src/java/org/apache/james/transport/LinearProcessor.java
Index: LinearProcessor.java
===================================================================
RCS file:
/home/cvs/jakarta-james/src/java/org/apache/james/transport/LinearProcessor.java,v
retrieving revision 1.10.4.2
retrieving revision 1.10.4.3
diff -u -r1.10.4.2 -r1.10.4.3
--- LinearProcessor.java 8 Mar 2003 21:54:07 -0000 1.10.4.2
+++ LinearProcessor.java 2 Jun 2003 05:40:27 -0000 1.10.4.3
@@ -73,7 +73,6 @@
import java.util.Collection;
import java.util.List;
import java.util.Random;
-import java.util.Vector;
import java.util.Iterator;
/**
@@ -369,19 +368,25 @@
try {
recipients = matcher.match(mail);
if (recipients == null) {
- //In case the matcher returned null, create an empty Vector
- recipients = new Vector();
+ //In case the matcher returned null, create an empty Collection
+ recipients = new ArrayList(0);
+ } else if (recipients != mail.getRecipients()) {
+ //Make sure all the objects are MailAddress objects
+ verifyMailAddresses(recipients);
}
- //Make sure all the objects are MailAddress objects
- verifyMailAddresses(recipients);
} catch (MessagingException me) {
handleException(me, mail,
matcher.getMatcherConfig().getMatcherName());
}
+
// Split the recipients into two pools. notRecipients will contain the
// recipients on the message that the matcher did not return.
- Collection notRecipients = new Vector();
- notRecipients.addAll(mail.getRecipients());
- notRecipients.removeAll(recipients);
+ Collection notRecipients;
+ if (recipients == mail.getRecipients() || recipients.size() == 0) {
+ notRecipients = new ArrayList(0);
+ } else {
+ notRecipients = new ArrayList(mail.getRecipients());
+ notRecipients.removeAll(recipients);
+ }
if (recipients.size() == 0) {
//Everything was not a match... store it in the next spot in the
array
No revision
No revision
1.18.4.4 +766 -213
jakarta-james/src/java/org/apache/james/transport/mailets/Redirect.java
Index: Redirect.java
===================================================================
RCS file:
/home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/Redirect.java,v
retrieving revision 1.18.4.3
retrieving revision 1.18.4.4
diff -u -r1.18.4.3 -r1.18.4.4
--- Redirect.java 12 Mar 2003 19:37:09 -0000 1.18.4.3
+++ Redirect.java 2 Jun 2003 05:40:28 -0000 1.18.4.4
@@ -68,7 +68,7 @@
import java.util.Iterator;
import java.util.Locale;
import java.util.StringTokenizer;
-import java.util.Vector;
+import java.util.ArrayList;
import javax.mail.Message;
@@ -81,6 +81,7 @@
import org.apache.james.util.RFC2822Headers;
import org.apache.james.util.RFC822DateFormat;
+import org.apache.james.core.MailImpl;
import org.apache.mailet.GenericMailet;
import org.apache.mailet.Mail;
@@ -104,9 +105,11 @@
*<LI>getMessage(), The text of the message itself</LI>
*<LI>getRecipients(), the recipients the mail is sent to</LI>
*<LI>getReplyTo(), where replys to this message will be sent</LI>
+*<LI>getReturnPath(), what to set the Return-Path to</LI>
*<LI>getSender(), who the mail is from</LI>
*<LI>getSubjectPrefix(), a prefix to be added to the message subject</LI>
*<LI>getTo(), a list of people to whom the mail is *apparently* sent</LI>
+*<LI>isReply(), should this mailet set the IN_REPLY_TO header to the id of the
current message</LI>
*<LI>getPassThrough(), should this mailet allow the original message to continue
processing or GHOST it.</LI>
*<LI>isStatic(), should this mailet run the get methods for every mail, or just
*once. </LI>
@@ -118,14 +121,16 @@
*<TD width="80%">A comma delimited list of email addresses for recipients of
*this message, it will use the "to" list if not specified. These
*addresses will only appear in the To: header if no "to" list is
-*supplied.</TD>
+*supplied.<BR>
+*It can include constants "sender" and "postmaster"</TD>
*</TR>
*<TR>
*<TD width="20%"><to></TD>
*<TD width="80%">A comma delimited list of addresses to appear in the To: header,
*the email will only be delivered to these addresses if they are in the recipients
*list.<BR>
-*The recipients list will be used if this is not supplied.</TD>
+*The recipients list will be used if this is not supplied.<BR>
+*It can include constants "sender", "postmaster" and
"unaltered"</TD>
*</TR>
*<TR>
*<TD width="20%"><sender></TD>
@@ -186,9 +191,15 @@
*</TR>
*<TR>
*<TD width="20%"><replyto></TD>
-*<TD width="80%">A single email address to appear in the Rely-To: header, can
+*<TD width="80%">A single email address to appear in the Reply-To: header, can
*also be "sender" or "postmaster", this header is not
-*set if this is omited.</TD>
+*set if this is omitted.</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><returnPath></TD>
+*<TD width="80%">A single email address to appear in the Return-Path: header, can
+*also be "sender" or "postmaster" or "null"; this
header is not
+*set if this parameter is omitted.</TD>
*</TR>
*<TR>
*<TD width="20%"><prefix></TD>
@@ -197,6 +208,11 @@
*Undeliverable mail: </TD>
*</TR>
*<TR>
+*<TD width="20%"><isReply></TD>
+*<TD width="80%">TRUE or FALSE, if true the IN_REPLY_TO header will be set to the
+*id of the current message.</TD>
+*</TR>
+*<TR>
*<TD width="20%"><static></TD>
*<TD width="80%">
*<P>TRUE or FALSE. If this is TRUE it tells the mailet that it can
@@ -204,8 +220,6 @@
*their values. This will boost performance where a redirect task
*doesn't contain any dynamic values. If this is FALSE, it tells the
*mailet to recalculate the values for each e-mail processed.</P>
-*<P>Note: If you use "magic words" such as "sender" in the <sender>
-*tag, you must NOT use set static to TRUE.</P>
*<P>This defaults to false.<BR>
*</TD>
*</TR>
@@ -240,69 +254,127 @@
*<static>TRUE</static><BR>
*</mailet></P>
*
- * @author Danny Angus <[EMAIL PROTECTED]>
*
*/
-public class Redirect extends GenericMailet {
+public class Redirect extends GenericMailet {
+
/**
* Controls certain log messages
*/
- private boolean isDebug = false;
+ protected boolean isDebug = false;
+
+ private static class AddressMarker {
+ public static MailAddress SENDER;
+ public static MailAddress TO;
+ public static MailAddress RECIPIENTS;
+ public static MailAddress DELETE;
+ public static MailAddress UNALTERED;
+ public static MailAddress NULL;
+
+ static {
+ try {
+ MailAddress SENDER = new
MailAddress("sender","Address.Marker");
+ MailAddress TO = new MailAddress("to","Address.Marker");
+ MailAddress RECIPIENTS = new
MailAddress("recipients","Address.Marker");
+ MailAddress DELETE = new
MailAddress("delete","Address.Marker");
+ MailAddress UNALTERED = new
MailAddress("unaltered","Address.Marker");
+ MailAddress NULL = new MailAddress("null","Address.Marker");
+
+ } catch (Exception _) {}
+ }
+ }
+
+ protected static class SpecialAddress {
+ public static final MailAddress SENDER = AddressMarker.SENDER;
+ public static final MailAddress TO = AddressMarker.TO;
+ public static final MailAddress RECIPIENTS = AddressMarker.RECIPIENTS;
+ public static final MailAddress DELETE = AddressMarker.DELETE;
+ public static final MailAddress UNALTERED = AddressMarker.UNALTERED;
+ public static final MailAddress NULL = AddressMarker.NULL;
+ }
// The values that indicate how to attach the original mail
- // to the redirected mail.
+ // to the new mail.
- private static final int UNALTERED = 0;
+ protected static final int UNALTERED = 0;
- private static final int HEADS = 1;
+ protected static final int HEADS = 1;
- private static final int BODY = 2;
+ protected static final int BODY = 2;
- private static final int ALL = 3;
+ protected static final int ALL = 3;
- private static final int NONE = 4;
+ protected static final int NONE = 4;
- private static final int MESSAGE = 5;
+ protected static final int MESSAGE = 5;
- private InternetAddress[] apparentlyTo;
+ private boolean isStatic = false;
+
+ private int attachmentType = NONE;
+ private int inLineType = BODY;
private String messageText;
private Collection recipients;
private MailAddress replyTo;
+ private MailAddress returnPath;
private MailAddress sender;
+ private String subjectPrefix;
+ private InternetAddress[] apparentlyTo;
+ private boolean attachError = false;
+ private boolean isReply = false;
private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
/**
- * returns one of these values to indicate how to attach the original
message
- *<ul>
- * <li>BODY : original message body is attached as plain text to the new
message</li>
- * <li>HEADS : original message headers are attached as plain text to the
new message</li>
- * <li>ALL : original is attached as plain text with all headers</li>
- * <li>MESSAGE : original message is attached as type message/rfc822, a
complete mail message.</li>
- * <li>NONE : original is not attached</li>
- *</ul>
+ * Returns a string describing this mailet.
*
+ * @return a string describing this mailet
*/
- public int getAttachmentType() {
- if(getInitParameter("attachment") == null) {
- return NONE;
+ public String getMailetInfo() {
+ return "Resend Mailet";
+ }
+
+ /**
+ * Gets the <CODE>passThrough</CODE> init parameter.
+ *
+ * @return true to allow the original message to continue through the
processor, false to GHOST it
+ */
+ protected boolean getPassThrough() {
+ if(getInitParameter("passThrough") == null) {
+ return false;
} else {
- return getTypeCode(getInitParameter("attachment"));
+ return new Boolean(getInitParameter("passThrough")).booleanValue();
}
}
/**
- * returns one of these values to indicate how to append the original message
- *<ul>
+ * Gets the <CODE>static</CODE> init parameter.
+ * return true to reduce calls to getTo, getSender, getRecipients, getReplyTo,
getReturnPath amd getMessage
+ * where these values don't change (eg hard coded, or got at startup from the
mailet config)<br>
+ * return false where any of these methods generate their results dynamically
eg in response to the message being processed,
+ * or by reference to a repository of users
+ * Is a "getX()" method.
+ */
+ protected boolean isStatic() {
+ return isStatic;
+ }
+
+ /**
+ * Gets the <CODE>inline</CODE> init parameter.
+ * May return one of the following values to indicate how to append the
original message
+ * to build the new message:
+ * <ul>
* <li>UNALTERED : original message is the new message body</li>
* <li>BODY : original message body is appended to the new message</li>
* <li>HEADS : original message headers are appended to the new message</li>
* <li>ALL : original is appended with all headers</li>
* <li>NONE : original is not appended</li>
- *</ul>
+ * </ul>
+ * Is a "getX()" method.
+ *
+ * @return the inline type value code
*/
- public int getInLineType() {
+ protected int getInLineType() throws MessagingException {
if(getInitParameter("inline") == null) {
return BODY;
} else {
@@ -311,45 +383,107 @@
}
/**
- * Return a string describing this mailet.
+ * Gets the <CODE>inline</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
*
- * @return a string describing this mailet
+ * @return [EMAIL PROTECTED] #getInlineType()}
*/
- public String getMailetInfo() {
- return "Resend Mailet";
+ protected int getInLineType(Mail originalMail) throws MessagingException {
+ int inLineType = (isStatic()) ? this.inLineType : getInLineType();
+ return inLineType;
}
/**
- * must return either an empty string, or a message to which the redirect can
be attached/appended
+ * Gets the <CODE>attachment</CODE> init parameter.
+ * May return one of the following values to indicate how to attach the
original message
+ * to the new message:
+ * <ul>
+ * <li>BODY : original message body is attached as plain text to the new
message</li>
+ * <li>HEADS : original message headers are attached as plain text to the
new message</li>
+ * <li>ALL : original is attached as plain text with all headers</li>
+ * <li>MESSAGE : original message is attached as type message/rfc822, a
complete mail message.</li>
+ * <li>NONE : original is not attached</li>
+ * </ul>
+ * Is a "getX()" method.
+ *
+ * @return the attachmentType value code
*/
- public String getMessage() {
- if(getInitParameter("message") == null) {
- return "";
+ protected int getAttachmentType() throws MessagingException {
+ if(getInitParameter("attachment") == null) {
+ return NONE;
} else {
- return getInitParameter("message");
+ return getTypeCode(getInitParameter("attachment"));
}
}
/**
- * return true to allow thie original message to continue through the
processor, false to GHOST it
+ * Gets the <CODE>attachment</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getAttachmentType()}
*/
- public boolean getPassThrough() {
- if(getInitParameter("passThrough") == null) {
- return false;
+ protected int getAttachmentType(Mail originalMail) throws MessagingException {
+ int attachmentType = (isStatic()) ? this.attachmentType :
getAttachmentType();
+ return attachmentType;
+ }
+
+ /**
+ * Gets the <CODE>message</CODE> init parameter.
+ * Returns a message to which the original message can be attached/appended
+ * to build the new message.
+ * Is a "getX()" method.
+ *
+ * @return the message or an empty string if parameter is missing
+ */
+ protected String getMessage() throws MessagingException {
+ if(getInitParameter("message") == null) {
+ return "";
} else {
- return new Boolean(getInitParameter("passThrough")).booleanValue();
+ return getInitParameter("message");
}
}
/**
- * must return a Collection of recipient MailAddresses
+ * Gets the <CODE>message</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getMessage()}
*/
- public Collection getRecipients() {
- Collection newRecipients = new HashSet();
- String addressList = (getInitParameter("recipients") ==
null)
- ? getInitParameter("to")
- : getInitParameter("recipients");
- StringTokenizer st = new StringTokenizer(addressList, ",",
false);
+ protected String getMessage(Mail originalMail) throws MessagingException {
+ String messageText = (isStatic()) ? this.messageText : getMessage();
+ return messageText;
+ }
+
+ /**
+ * Gets the <CODE>recipients</CODE> init parameter.
+ * Returns the collection of recipients of the new message.
+ * If the <CODE>recipients</CODE> init parameter is missing,
+ * returns the <CODE>to</CODE> init parameter.
+ * Is a "getX()" method.
+ *
+ * @return the addresses or SENDER or null if missing
+ */
+ protected Collection getRecipients() throws MessagingException {
+ Collection newRecipients = new HashSet();
+ String addressList = (getInitParameter("recipients") == null)
+ ? getInitParameter("to")
+ : getInitParameter("recipients");
+ // if nothing was specified, return null meaning no change
+ if (addressList == null) {
+ return null;
+ }
+ if(addressList.compareTo("postmaster") == 0) {
+ newRecipients.add(getMailetContext().getPostmaster());
+ return newRecipients;
+ }
+ if(addressList.compareTo("sender") == 0) {
+ newRecipients.add(SpecialAddress.SENDER);
+ return newRecipients;
+ }
+ StringTokenizer st = new StringTokenizer(addressList, ",", false);
while(st.hasMoreTokens()) {
try {
newRecipients.add(new MailAddress(st.nextToken()));
@@ -361,11 +495,123 @@
}
/**
- * Returns the reply to address as a string.
+ * Gets the <CODE>recipients</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getRecipients()}, replacing SENDER if applicable
+ */
+ protected Collection getRecipients(Mail originalMail) throws MessagingException
{
+ // TODO: implement MailAddress.RETURN_PATH
+ Collection recipients = (isStatic()) ? this.recipients : getRecipients();
+ if (recipients != null && recipients.size() == 1) {
+ if (recipients.contains(SpecialAddress.SENDER)) {
+ recipients = new ArrayList();
+ recipients.add(originalMail.getSender());
+ }
+ }
+ return recipients;
+ }
+
+ /**
+ * Sets the recipients of <I>newMail</I> to <I>recipients</I>.
+ */
+ protected void setRecipients(Mail newMail, Collection recipients, Mail
originalMail) throws MessagingException {
+ if (recipients != null) {
+ ((MailImpl) newMail).setRecipients(recipients);
+ if (isDebug) {
+ log("recipients set to: " + arrayToString(recipients.toArray()));
+ }
+ }
+ }
+
+ /**
+ * Gets the <CODE>to</CODE> init parameter.
+ * Returns the "To:" recipients of the new message.
+ * If the <CODE>to</CODE> init parameter is missing,
+ * returns the <CODE>recipients</CODE> init parameter.
+ * Is a "getX()" method.
+ *
+ * @return the addresses or SENDER or UNALTERED or null meaning no change
+ */
+ protected InternetAddress[] getTo() throws MessagingException {
+ String addressList = (getInitParameter("to") == null)
+ ? getInitParameter("recipients")
+ : getInitParameter("to");
+ // if nothing was specified, return null meaning no change
+ if (addressList == null) {
+ return null;
+ }
+ if(addressList.compareTo("postmaster") == 0) {
+ InternetAddress[] iaarray = new InternetAddress[1];
+ iaarray[0] = getMailetContext().getPostmaster().toInternetAddress();
+ return iaarray;
+ }
+ if(addressList.compareTo("sender") == 0) {
+ InternetAddress[] iaarray = new InternetAddress[1];
+ iaarray[0] = SpecialAddress.SENDER.toInternetAddress();
+ return iaarray;
+ }
+ if(addressList.compareTo("unaltered") == 0) {
+ InternetAddress[] iaarray = new InternetAddress[1];
+ iaarray[0] = SpecialAddress.UNALTERED.toInternetAddress();
+ return iaarray;
+ }
+ StringTokenizer rec = new StringTokenizer(addressList, ",");
+ int tokensn = rec.countTokens();
+ InternetAddress[] iaarray = new InternetAddress[tokensn];
+ String tokenx = "";
+ for(int i = 0; i < tokensn; ++i) {
+ try {
+ tokenx = rec.nextToken();
+ iaarray[i] = new InternetAddress(tokenx);
+ } catch(Exception e) {
+ log("Internet address exception in getTo()");
+ }
+ }
+ return iaarray;
+ }
+
+ /**
+ * Gets the <CODE>to</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getTo()}, replacing SENDER and UNALTERED if
applicable
+ */
+ protected InternetAddress[] getTo(Mail originalMail) throws MessagingException {
+ InternetAddress[] apparentlyTo = (isStatic()) ? this.apparentlyTo : getTo();
+ if (apparentlyTo != null && apparentlyTo.length == 1) {
+ if (apparentlyTo[0].equals(SpecialAddress.SENDER.toInternetAddress())) {
+ apparentlyTo = new InternetAddress[1];
+ apparentlyTo[0] = originalMail.getSender().toInternetAddress();
+ } else if
(apparentlyTo[0].equals(SpecialAddress.UNALTERED.toInternetAddress())) {
+ apparentlyTo = (InternetAddress[])
originalMail.getMessage().getRecipients(Message.RecipientType.TO);
+ }
+ }
+ return apparentlyTo;
+ }
+
+ /**
+ * Sets the "To:" header of <I>newMail</I> to <I>to</I>.
+ */
+ protected void setTo(Mail newMail, InternetAddress[] to, Mail originalMail)
throws MessagingException {
+ if (to != null) {
+ newMail.getMessage().setRecipients(Message.RecipientType.TO, to);
+ if (isDebug) {
+ log("apparentlyTo set to: " + arrayToString(to));
+ }
+ }
+ }
+
+ /**
+ * Gets the <CODE>replyto</CODE> init parameter.
+ * Returns the Reply-To address of the new message.
+ * Is a "getX()" method.
*
- * @return the replyto address for the mail as a string
+ * @return an address or null if parameter is missing or == "sender" (null
means "use original")
*/
- public MailAddress getReplyTo() {
+ protected MailAddress getReplyTo() throws MessagingException {
String sr = getInitParameter("replyto");
if(sr != null) {
MailAddress rv;
@@ -374,6 +620,7 @@
return rv;
}
if(sr.compareTo("sender") == 0) {
+ // means no change
return null;
}
try {
@@ -387,9 +634,104 @@
}
/**
- * returns the senders address, as a MailAddress
+ * Gets the <CODE>replyTo</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getReplyTo()}
+ */
+ protected MailAddress getReplyTo(Mail originalMail) throws MessagingException {
+ MailAddress replyTo = (isStatic()) ? this.replyTo : getReplyTo();
+ return replyTo;
+ }
+
+ /**
+ * Sets the "Reply-To:" header of <I>newMail</I> to <I>replyTo</I>.
+ */
+ protected void setReplyTo(Mail newMail, MailAddress replyTo, Mail originalMail)
throws MessagingException {
+ if(replyTo != null) {
+ InternetAddress[] iart = new InternetAddress[1];
+ iart[0] = replyTo.toInternetAddress();
+ newMail.getMessage().setReplyTo(iart);
+ if (isDebug) {
+ log("replyTo set to: " + replyTo);
+ }
+ }
+ }
+
+ /**
+ * Gets the <CODE>returnPath</CODE> init parameter.
+ * Returns the Return-Path of the new message.
+ * Is a "getX()" method.
+ *
+ * @return an address or NULL or SENDER or null if parameter is missing (null
means "use original")
+ */
+ protected MailAddress getReturnPath() throws MessagingException {
+ String sr = getInitParameter("returnPath");
+ if(sr != null) {
+ MailAddress rv;
+ if(sr.compareTo("postmaster") == 0) {
+ return getMailetContext().getPostmaster();
+ }
+ if(sr.compareTo("NULL") == 0) {
+ return SpecialAddress.NULL;
+ }
+ if(sr.compareTo("sender") == 0) {
+ return SpecialAddress.SENDER;
+ }
+ try {
+ rv = new MailAddress(sr);
+ return rv;
+ } catch(Exception e) {
+ log("Parse error in getReturnPath " + sr);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the <CODE>returnPath</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getReturnPath()}, replacing SENDER if applicable,
but not replacing NULL
+ */
+ protected MailAddress getReturnPath(Mail originalMail) throws
MessagingException {
+ MailAddress returnPath = (isStatic()) ? this.returnPath : getReturnPath();
+ if (returnPath != null) {
+ if (returnPath == SpecialAddress.SENDER) {
+ returnPath = originalMail.getSender();
+ }
+ }
+ return returnPath;
+ }
+
+ /**
+ * Sets the "Return-Path:" header of <I>newMail</I> to <I>returnPath</I>.
+ */
+ protected void setReturnPath(Mail newMail, MailAddress returnPath, Mail
originalMail) throws MessagingException {
+ if(returnPath != null) {
+ String returnPathString;
+ if (returnPath == SpecialAddress.NULL) {
+ returnPathString = "";
+ } else {
+ returnPathString = returnPath.toString();
+ }
+ newMail.getMessage().setHeader(RFC2822Headers.RETURN_PATH, "<" +
returnPathString + ">");
+ if (isDebug) {
+ log("returnPath set to: " + returnPath);
+ }
+ }
+ }
+
+ /**
+ * Gets the <CODE>sender</CODE> init parameter.
+ * Returns the new sender as a MailAddress.
+ * Is a "getX()" method.
+ *
+ * @return an address or null if parameter is missing or == "sender", meaning
"use original"
*/
- public MailAddress getSender() {
+ protected MailAddress getSender() throws MessagingException {
String sr = getInitParameter("sender");
if(sr != null) {
MailAddress rv;
@@ -398,6 +740,7 @@
return rv;
}
if(sr.compareTo("sender") == 0) {
+ // means no change: use FROM header; kept as is for compatibility
return null;
}
try {
@@ -411,22 +754,43 @@
}
/**
- * return true to reduce calls to getTo, getSender, getRecipients, getReplyTo
amd getMessage
- * where these values don't change (eg hard coded, or got at startup from the
mailet config)<br>
- * return false where any of these methods generate their results dynamically
eg in response to the message being processed,
- * or by refrence to a repository of users
+ * Gets the <CODE>sender</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getSender()}
*/
- public boolean isStatic() {
- if(getInitParameter("static") == null) {
- return false;
+ protected MailAddress getSender(Mail originalMail) throws MessagingException {
+ MailAddress sender = (isStatic()) ? this.sender : getSender();
+ return sender;
+ }
+
+ /**
+ * Sets the sender and the "From:" header of <I>newMail</I> to <I>sender</I>.
+ * If sender is null will set such values to the ones in <I>originalMail</I>.
+ */
+ protected void setSender(Mail newMail, MailAddress sender, Mail originalMail)
throws MessagingException {
+ if (sender == null) {
+ MailAddress originalSender = new MailAddress(((InternetAddress)
originalMail.getMessage().getFrom()[0]).getAddress());
+ newMail.getMessage().setHeader(RFC2822Headers.FROM,
originalMail.getMessage().getHeader(RFC2822Headers.FROM, ","));
+ ((MailImpl) newMail).setSender(originalSender);
+ } else {
+ newMail.getMessage().setFrom(sender.toInternetAddress());
+ ((MailImpl) newMail).setSender(sender);
+ if (isDebug) {
+ log("sender set to: " + sender);
+ }
}
- return new Boolean(getInitParameter("static")).booleanValue();
}
-
+
/**
- * return a prefix for the message subject
+ * Gets the <CODE>prefix</CODE> init parameter.
+ * Returns a prefix for the new message subject.
+ * Is a "getX()" method.
+ *
+ * @return the prefix or an empty string if parameter is missing
*/
- public String getSubjectPrefix() {
+ protected String getSubjectPrefix() throws MessagingException {
if(getInitParameter("prefix") == null) {
return "";
} else {
@@ -435,31 +799,41 @@
}
/**
- * returns an array of InternetAddress 'es for the To: header
+ * Gets the <CODE>subjectPrefix</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #getSubjectPrefix()}
*/
- public InternetAddress[] getTo() {
- String addressList = (getInitParameter("to") == null)
- ? getInitParameter("recipients") :
getInitParameter("to");
- StringTokenizer rec = new StringTokenizer(addressList, ",");
- int tokensn = rec.countTokens();
- InternetAddress[] iaarray = new InternetAddress[tokensn];
- String tokenx = "";
- for(int i = 0; i < tokensn; ++i) {
- try {
- tokenx = rec.nextToken();
- iaarray[i] = new InternetAddress(tokenx);
- } catch(Exception e) {
- log("Internet address exception in getTo()");
- }
+ protected String getSubjectPrefix(Mail originalMail) throws MessagingException {
+ String subjectPrefix = (isStatic()) ? this.subjectPrefix :
getSubjectPrefix();
+ return subjectPrefix;
+ }
+
+ /**
+ * Builds the subject of <I>newMail</I> appending the subject
+ * of <I>originalMail</I> to <I>subjectPrefix</I>.
+ */
+ protected void setSubjectPrefix(Mail newMail, String subjectPrefix, Mail
originalMail) throws MessagingException {
+ String subject = originalMail.getMessage().getSubject();
+ if (subject == null) {
+ subject = "";
+ }
+ newMail.getMessage().setSubject(subjectPrefix + subject);
+ if (isDebug) {
+ log("subjectPrefix set to: " + subjectPrefix);
}
- return iaarray;
}
-
+
/**
- * return true to append a description of any error to the main body part
- * if getInlineType does not return "UNALTERED"
+ * Gets the <CODE>attachError</CODE> init parameter.
+ * Returns a boolean indicating whether to append a description of any error to
the main body part
+ * of the new message, if getInlineType does not return "UNALTERED".
+ * Is a "getX()" method.
+ *
+ * @return true or false; false if init parameter missing
*/
- public boolean attachError() {
+ protected boolean attachError() throws MessagingException {
if(getInitParameter("attachError") == null) {
return false;
} else {
@@ -468,31 +842,101 @@
}
/**
- * init will setup static values for sender, recipients, message text, and
reply to
- * <br> if isStatic() returns true
- * it calls getSender(), getReplyTo(), getMessage(), and getRecipients() and
getTo()
- *
- */
+ * Gets the <CODE>attachError</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #attachError()}
+ */
+ protected boolean attachError(Mail originalMail) throws MessagingException {
+ boolean attachError = (isStatic()) ? this.attachError : attachError();
+ return attachError;
+ }
+
+ /**
+ * Gets the <CODE>isReply</CODE> init parameter.
+ * Returns a boolean indicating whether the new message must be considered
+ * a reply to the original message, setting the IN_REPLY_TO header of the new
+ * message to the id of the original message.
+ * Is a "getX()" method.
+ *
+ * @return true or false; false if init parameter missing
+ */
+ protected boolean isReply() throws MessagingException {
+ if(getInitParameter("isReply") == null) {
+ return false;
+ }
+ return new Boolean(getInitParameter("isReply")).booleanValue();
+ }
+
+ /**
+ * Gets the <CODE>isReply</CODE> init parameter,
+ * built dynamically using the original Mail object.
+ * Is a "getX(Mail)" method.
+ *
+ * @return [EMAIL PROTECTED] #isReply()}
+ */
+ protected boolean isReply(Mail originalMail) throws MessagingException {
+ boolean isReply = (isStatic()) ? this.isReply : isReply();
+ return isReply;
+ }
+
+ /**
+ * Sets the "In-Reply-To:" header of <I>newMail</I> to the "Message-Id:" of
+ * <I>originalMail</I>, if <I>isReply</I> is true.
+ */
+ protected void setIsReply(Mail newMail, boolean isReply, Mail originalMail)
throws MessagingException {
+ if (isReply) {
+ String messageId = originalMail.getMessage().getMessageID();
+ if (messageId != null) {
+ newMail.getMessage().setHeader(RFC2822Headers.IN_REPLY_TO,
messageId);
+ if (isDebug) {
+ log("IN_REPLY_TO set to: " + messageId);
+ }
+ }
+ }
+ }
+
+ /**
+ * Mailet initialization routine.
+ * Will setup static values for each "x" initialization parameter in config.xml,
+ * using getX(), if isStatic() returns true.
+ *
+ */
public void init() throws MessagingException {
if (isDebug) {
log("Redirect init");
}
isDebug = (getInitParameter("debug") == null) ? false : new
Boolean(getInitParameter("debug")).booleanValue();
+
+ isStatic = (getInitParameter("static") == null) ? false : new
Boolean(getInitParameter("static")).booleanValue();
+
if(isStatic()) {
- sender = getSender();
- replyTo = getReplyTo();
- messageText = getMessage();
- recipients = getRecipients();
- apparentlyTo = getTo();
+ attachmentType = getAttachmentType();
+ inLineType = getInLineType();
+ messageText = getMessage();
+ recipients = getRecipients();
+ replyTo = getReplyTo();
+ returnPath = getReturnPath();
+ sender = getSender();
+ subjectPrefix = getSubjectPrefix();
+ apparentlyTo = getTo();
+ attachError = attachError();
+ isReply = isReply();
if (isDebug) {
StringBuffer logBuffer =
new StringBuffer(1024)
- .append("static, sender=")
- .append(sender)
- .append(", replyTo=")
- .append(replyTo)
- .append(", message=")
- .append(messageText)
+ .append("static, sender=").append(sender)
+ .append(", replyTo=").append(replyTo)
+ .append(", returnPath=").append(returnPath)
+ .append(", message=").append(messageText)
+ .append(",
recipients=").append(arrayToString(recipients.toArray()))
+ .append(", subjectPrefix=").append(subjectPrefix)
+ .append(",
apparentlyTo=").append(arrayToString(apparentlyTo))
+ .append(", attachError=").append(attachError)
+ .append(", isReply=").append(isReply)
+ .append(", attachmentType=").append(attachmentType)
+ .append(", inLineType=").append(inLineType)
.append(" ");
log(logBuffer.toString());
}
@@ -500,133 +944,103 @@
}
/**
- * Service does the hard work,and redirects the mail in the form specified
+ * Service does the hard work,and redirects the originalMail in the form
specified.
*
- * @param mail the mail to process and redirect
- * @throws MessagingException if a problem arising formulating the redirected
mail
+ * @param originalMail the mail to process and redirect
+ * @throws MessagingException if a problem arises formulating the redirected
mail
*/
- public void service(Mail mail) throws MessagingException {
- if(!isStatic()) {
- sender = getSender();
- replyTo = getReplyTo();
- messageText = getMessage();
- recipients = getRecipients();
- apparentlyTo = getTo();
- }
+ public void service(Mail originalMail) throws MessagingException {
+
+ boolean keepMessageId = false;
- MimeMessage message = mail.getMessage();
- MimeMessage reply = null;
+ // duplicates the Mail object, to be able to modify the new mail keeping
the original untouched
+ Mail newMail = ((MailImpl)
originalMail).duplicate(newName((MailImpl)originalMail));
+
+ if (isDebug) {
+ MailImpl newMailImpl = (MailImpl) newMail;
+ log("New mail - sender: " + newMailImpl.getSender()
+ + ", recipients: " +
arrayToString(newMailImpl.getRecipients().toArray())
+ + ", name: " + newMailImpl.getName()
+ + ", remoteHost: " + newMailImpl.getRemoteHost()
+ + ", remoteAddr: " + newMailImpl.getRemoteAddr()
+ + ", state: " + newMailImpl.getState()
+ + ", lastUpdated: " + newMailImpl.getLastUpdated()
+ + ", errorMessage: " + newMailImpl.getErrorMessage());
+ }
+
//Create the message
- if(getInLineType() != UNALTERED) {
+ if(getInLineType(originalMail) != UNALTERED) {
if (isDebug) {
- log("Alter message inline=:" + getInLineType());
- }
- reply = new
MimeMessage(Session.getDefaultInstance(System.getProperties(),
- null));
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- Enumeration heads = message.getAllHeaderLines();
- String head = "";
- StringBuffer headBuffer = new StringBuffer(1024);
- while(heads.hasMoreElements()) {
- headBuffer.append(heads.nextElement().toString()).append("\n");
- }
- head = headBuffer.toString();
- boolean all = false;
- if(messageText != null) {
- out.println(messageText);
- }
- switch(getInLineType()) {
- case ALL: //ALL:
- all = true;
- case HEADS: //HEADS:
- out.println("Message Headers:");
- out.println(head);
- if(!all) {
- break;
- }
- case BODY: //BODY:
- out.println("Message:");
- try {
- out.println(message.getContent().toString());
- } catch(Exception e) {
- out.println("body unavailable");
- }
- break;
- default:
- case NONE: //NONE:
- break;
- }
- MimeMultipart multipart = new MimeMultipart();
- //Add message as the first mime body part
- MimeBodyPart part = new MimeBodyPart();
- part.setText(sout.toString());
- part.setDisposition("inline");
- multipart.addBodyPart(part);
- if(getAttachmentType() != NONE) {
- part = new MimeBodyPart();
- switch(getAttachmentType()) {
- case HEADS: //HEADS:
- part.setText(head);
- break;
- case BODY: //BODY:
- try {
- part.setText(message.getContent().toString());
- } catch(Exception e) {
- part.setText("body unavailable");
- }
- break;
- case ALL: //ALL:
- StringBuffer textBuffer =
- new StringBuffer(1024)
- .append(head)
- .append("\n\n")
- .append(message.toString());
- part.setText(textBuffer.toString());
- break;
- case MESSAGE: //MESSAGE:
- part.setContent(message, "message/rfc822");
- break;
- }
- part.setDisposition("Attachment");
- multipart.addBodyPart(part);
+ log("Alter message inline=:" + getInLineType(originalMail));
}
- reply.setContent(multipart);
- reply.setHeader(RFC2822Headers.CONTENT_TYPE,
multipart.getContentType());
- reply.setRecipients(Message.RecipientType.TO, apparentlyTo);
+ newMail.setMessage(new
MimeMessage(Session.getDefaultInstance(System.getProperties(),
+ null)));
+
+ // handle the new message if altered
+ buildAlteredMessage(newMail, originalMail);
+
+ setTo(newMail, getTo(originalMail), originalMail);
+
} else {
// if we need the original, create a copy of this message to redirect
- reply = getPassThrough() ? new MimeMessage(message) : message;
+ if (getPassThrough()) {
+ newMail.setMessage(new MimeMessage(originalMail.getMessage()));
+ }
if (isDebug) {
log("Message resent unaltered.");
}
+ keepMessageId = true;
}
+
//Set additional headers
- reply.setSubject(getSubjectPrefix() + message.getSubject());
- if(reply.getHeader(RFC2822Headers.DATE) == null) {
- reply.setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new
Date()));
- }
- //
-
- if(replyTo != null) {
- InternetAddress[] iart = new InternetAddress[1];
- iart[0] = replyTo.toInternetAddress();
- reply.setReplyTo(iart);
+ setRecipients(newMail, getRecipients(originalMail), originalMail);
+
+ setSubjectPrefix(newMail, getSubjectPrefix(originalMail), originalMail);
+
+ if(newMail.getMessage().getHeader(RFC2822Headers.DATE) == null) {
+ newMail.getMessage().setHeader(RFC2822Headers.DATE,
rfc822DateFormat.format(new Date()));
}
- if(sender == null) {
- reply.setHeader(RFC2822Headers.FROM,
message.getHeader(RFC2822Headers.FROM, ","));
- sender = new
MailAddress(((InternetAddress)message.getFrom()[0]).getAddress());
- } else {
- reply.setFrom(sender.toInternetAddress());
+
+ setReplyTo(newMail, getReplyTo(originalMail), originalMail);
+
+ setReturnPath(newMail, getReturnPath(originalMail), originalMail);
+
+ setSender(newMail, getSender(originalMail), originalMail);
+
+ setIsReply(newMail, isReply(originalMail), originalMail);
+
+ newMail.getMessage().saveChanges();
+
+ if (keepMessageId) {
+ setMessageId(newMail, originalMail);
}
+
//Send it off...
- getMailetContext().sendMail(sender, recipients, reply);
+ getMailetContext().sendMail(newMail);
+
if(!getPassThrough()) {
- mail.setState(Mail.GHOST);
+ originalMail.setState(Mail.GHOST);
}
}
+ private static final java.util.Random random = new java.util.Random(); // Used
to generate new mail names
+ /**
+ * Create a unique new primary key name.
+ *
+ * @param mail the mail to use as the basis for the new mail name
+ *
+ * @return a new name
+ */
+ private String newName(MailImpl mail) {
+ StringBuffer nameBuffer =
+ new StringBuffer(64)
+ .append(mail.getName())
+ .append("-!")
+ .append(random.nextInt(1048576));
+ return nameBuffer.toString();
+ }
+
/**
* A private method to convert types from string to int.
*
@@ -656,5 +1070,144 @@
return MESSAGE;
}
return NONE;
+ }
+
+ /**
+ * Utility method for obtaining a string representation of an array of Objects.
+ */
+ private String arrayToString(Object[] array) {
+ StringBuffer sb = new StringBuffer(1024);
+ sb.append("[");
+ for (int i = 0; i < array.length; i++) {
+ sb.append(array[i]);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * Builds the message of the newMail in case it has to be altered.
+ *
+ * @param originalMail the original Mail object
+ * @param newMail the Mail object to build
+ */
+ protected void buildAlteredMessage(Mail newMail, Mail originalMail) throws
MessagingException {
+
+ MimeMessage message = originalMail.getMessage();
+
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ Enumeration heads = message.getAllHeaderLines();
+ String head = "";
+ StringBuffer headBuffer = new StringBuffer(1024);
+ while(heads.hasMoreElements()) {
+ headBuffer.append(heads.nextElement().toString()).append("\n");
+ }
+ head = headBuffer.toString();
+ boolean all = false;
+
+ String messageText = getMessage(originalMail);
+ if(messageText != null) {
+ out.println(messageText);
+ }
+
+ switch(getInLineType(originalMail)) {
+ case ALL: //ALL:
+ all = true;
+ case HEADS: //HEADS:
+ out.println("Message Headers:");
+ out.println(head);
+ if(!all) {
+ break;
+ }
+ case BODY: //BODY:
+ out.println("Message:");
+ try {
+ out.println(message.getContent().toString());
+ } catch(Exception e) {
+ out.println("body unavailable");
+ }
+ break;
+ default:
+ case NONE: //NONE:
+ break;
+ }
+
+ try {
+ //Create the message body
+ MimeMultipart multipart = new MimeMultipart("mixed");
+
+ // Create the message
+ MimeMultipart mpContent = new MimeMultipart("alternative");
+ MimeBodyPart contentPartRoot = new MimeBodyPart();
+ contentPartRoot.setContent(mpContent);
+
+ multipart.addBodyPart(contentPartRoot);
+
+ MimeBodyPart part = new MimeBodyPart();
+ part.setText(sout.toString());
+ part.setDisposition("inline");
+ mpContent.addBodyPart(part);
+ if(getAttachmentType() != NONE) {
+ part = new MimeBodyPart();
+ switch(getAttachmentType()) {
+ case HEADS: //HEADS:
+ part.setText(head);
+ break;
+ case BODY: //BODY:
+ try {
+ part.setText(message.getContent().toString());
+ } catch(Exception e) {
+ part.setText("body unavailable");
+ }
+ break;
+ case ALL: //ALL:
+ StringBuffer textBuffer =
+ new StringBuffer(1024)
+ .append(head)
+ .append("\n\n")
+ .append(message.toString());
+ part.setText(textBuffer.toString());
+ break;
+ case MESSAGE: //MESSAGE:
+ part.setContent(message, "message/rfc822");
+ break;
+ }
+ if ((message.getSubject() != null) &&
(message.getSubject().trim().length() > 0)) {
+ part.setFileName(message.getSubject().trim());
+ } else {
+ part.setFileName("No Subject");
+ }
+ part.setDisposition("Attachment");
+ multipart.addBodyPart(part);
+ }
+ //if set, attach the full stack trace
+ if (attachError(originalMail) && originalMail.getErrorMessage() !=
null) {
+ part = new MimeBodyPart();
+ part.setContent(originalMail.getErrorMessage(), "text/plain");
+ part.setHeader(RFC2822Headers.CONTENT_TYPE, "text/plain");
+ part.setFileName("Reasons");
+ part.setDisposition(javax.mail.Part.ATTACHMENT);
+ multipart.addBodyPart(part);
+ }
+ newMail.getMessage().setContent(multipart);
+ newMail.getMessage().setHeader(RFC2822Headers.CONTENT_TYPE,
multipart.getContentType());
+
+ } catch (Exception ioe) {
+ throw new MessagingException("Unable to create multipart body", ioe);
+ }
+ }
+
+ /**
+ * Sets the message id of originalMail into newMail.
+ */
+ private void setMessageId(Mail newMail, Mail originalMail) throws
MessagingException {
+ String messageId = originalMail.getMessage().getMessageID();
+ if (messageId != null) {
+ newMail.getMessage().setHeader(RFC2822Headers.MESSAGE_ID, messageId);
+ if (isDebug) {
+ log("MESSAGE_ID restored to: " + messageId);
+ }
+ }
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]