FileDocCategorySizeDatePackage
AbstractRedirect.javaAPI DocApache James 2.3.172016Fri Jan 12 12:56:28 GMT 2007org.apache.james.transport.mailets

AbstractRedirect

public abstract class AbstractRedirect extends org.apache.mailet.GenericMailet

Abstract mailet providing configurable redirection services.
This mailet can be subclassed to make authoring redirection mailets simple.
By extending it and overriding one or more of these methods new behaviour can be quickly created without the author having to address any other issue than the relevant one:

  • attachError() , should error messages be appended to the message
  • getAttachmentType(), what should be attached to the message
  • getInLineType(), what should be included in the message
  • getMessage(), The text of the message itself
  • getRecipients(), the recipients the mail is sent to
  • getReplyTo(), where replies to this message will be sent
  • getReversePath(), what to set the reverse-path to
  • getSender(), who the mail is from
  • getSubject(), a string to replace the message subject
  • getSubjectPrefix(), a prefix to be added to the message subject, possibly already replaced by a new subject
  • getTo(), a list of people to whom the mail is *apparently* sent
  • isReply(), should this mailet set the IN_REPLY_TO header to the id of the current message
  • getPassThrough(), should this mailet allow the original message to continue processing or GHOST it.
  • getFakeDomainCheck(), should this mailet check if the sender domain address is valid.
  • isStatic(), should this mailet run the get methods for every mail, or just once.

For each of the methods above (generically called "getX()" methods in this class and its subclasses), there is an associated "getX(Mail)" method and most times a "setX(Mail, Tx, Mail)" method.
The roles are the following:

  • a "getX()" method returns the correspondent "X" value that can be evaluated "statically" once at init time and then stored in a variable and made available for later use by a "getX(Mail)" method;
  • a "getX(Mail)" method is the one called to return the correspondent "X" value that can be evaluated "dynamically", tipically based on the currently serviced mail; the default behaviour is to return the value of getX();
  • a "setX(Mail, Tx, Mail)" method is called to change the correspondent "X" value of the redirected Mail object, using the value returned by "gexX(Mail)"; if such value is null, it does nothing.

Here follows the typical pattern of those methods:


...
Tx x;
...
protected boolean getX(Mail originalMail) throws MessagingException {
boolean x = (isStatic()) ? this.x : getX();
...
return x;
}
...
public void init() throws MessagingException {
...
isStatic = (getInitParameter("static") == null) ? false : new Boolean(getInitParameter("static")).booleanValue();
if(isStatic()) {
...
X = getX();
...
}
...
public void service(Mail originalMail) throws MessagingException {
...
setX(newMail, getX(originalMail), originalMail);
...
}
...

The isStatic variable and method is used to allow for the situations (deprecated since version 2.2, but possibly used by previoulsy written extensions to {@link Redirect}) in which the getX() methods are non static: in this case {@link #isStatic()} must return false.
Finally, a "getX()" method may return a "special address" (see {@link SpecialAddress}), that later will be resolved ("late bound") by a "getX(Mail)" or "setX(Mail, Tx, Mail)": it is a dynamic value that does not require isStatic to be false.

Supports by default the passThrough init parameter (false if missing). Subclasses can override this behaviour overriding {@link #getPassThrough()}.

version
CVS $Revision: 494012 $ $Date: 2007-01-08 11:23:58 +0100 (Mo, 08 Jan 2007) $
since
2.2.0

Fields Summary
protected boolean
isDebug
Controls certain log messages.
protected boolean
isStatic
Holds the value of the static init parameter.
protected static final int
UNALTERED
protected static final int
HEADS
protected static final int
BODY
protected static final int
ALL
protected static final int
NONE
protected static final int
MESSAGE
private boolean
passThrough
private boolean
fakeDomainCheck
private int
attachmentType
private int
inLineType
private String
messageText
private Collection
recipients
private org.apache.mailet.MailAddress
replyTo
private org.apache.mailet.MailAddress
reversePath
private org.apache.mailet.MailAddress
sender
private String
subject
private String
subjectPrefix
private InternetAddress[]
apparentlyTo
private boolean
attachError
private boolean
isReply
private org.apache.mailet.dates.RFC822DateFormat
rfc822DateFormat
private static final Random
random
Constructors Summary
Methods Summary
private java.lang.StringarrayToString(java.lang.Object[] array)
Utility method for obtaining a string representation of an array of Objects.

        if (array == null) {
            return "null";
        }
        StringBuffer sb = new StringBuffer(1024);
        sb.append("[");
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                sb.append(",");
            }
            sb.append(array[i]);
        }
        sb.append("]");
        return sb.toString();
    
protected booleanattachError()
Gets the attachError property. 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
the attachError init parameter; false if missing

        return new Boolean(getInitParameter("attachError")).booleanValue();
    
protected booleanattachError(org.apache.mailet.Mail originalMail)
Gets the attachError property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #attachError()}

        return (isStatic()) ? this.attachError : attachError();
    
protected voidbuildAlteredMessage(org.apache.mailet.Mail newMail, org.apache.mailet.Mail originalMail)
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


        MimeMessage originalMessage = originalMail.getMessage();
        MimeMessage newMessage = newMail.getMessage();

        // Copy the relevant headers
        String[] relevantHeaderNames =
            {RFC2822Headers.DATE,
             RFC2822Headers.FROM,
             RFC2822Headers.REPLY_TO,
             RFC2822Headers.TO,
             RFC2822Headers.SUBJECT,
             RFC2822Headers.RETURN_PATH};
        Enumeration headerEnum = originalMessage.getMatchingHeaderLines(relevantHeaderNames);
        while (headerEnum.hasMoreElements()) {
            newMessage.addHeaderLine((String) headerEnum.nextElement());
        }

        StringWriter sout = new StringWriter();
        PrintWriter out   = new PrintWriter(sout, true);
        String head = getMessageHeaders(originalMessage);
        boolean all = false;

        String messageText = getMessage(originalMail);
        if(messageText != null) {
            out.println(messageText);
        }

        if (isDebug) {
            log("inline:" + getInLineType(originalMail));
        }
        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(getMessageBody(originalMessage));
                } 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 (isDebug) {
                log("attachmentType:" + getAttachmentType(originalMail));
            }
            if(getAttachmentType(originalMail) != NONE) {
                part = new MimeBodyPart();
                switch(getAttachmentType(originalMail)) {
                    case HEADS: //HEADS:
                        part.setText(head);
                        break;
                    case BODY: //BODY:
                        try {
                            part.setText(getMessageBody(originalMessage));
                        } catch(Exception e) {
                            part.setText("body unavailable");
                        }
                        break;
                    case ALL: //ALL:
                        StringBuffer textBuffer =
                            new StringBuffer(1024)
                                .append(head)
                                .append("\r\nMessage:\r\n")
                                .append(getMessageBody(originalMessage));
                        part.setText(textBuffer.toString());
                        break;
                    case MESSAGE: //MESSAGE:
                        part.setContent(originalMessage, "message/rfc822");
                        break;
                }
                if ((originalMessage.getSubject() != null) && (originalMessage.getSubject().trim().length() > 0)) {
                    part.setFileName(originalMessage.getSubject().trim());
                } else {
                    part.setFileName("No Subject");
                }
                part.setDisposition("Attachment");
                multipart.addBodyPart(part);
            }
            //if set, attach the original mail's error message
            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);
        }
    
public static voidchangeSubject(javax.mail.internet.MimeMessage message, java.lang.String newValue)
It changes the subject of the supplied message to to supplied value but it also tries to preserve the original charset information.
This method was needed to avoid sending the subject using a charset (usually the default charset on the server) which doesn't contain the characters in the subject, resulting in the loss of these characters. The most simple method would be to either send it in ASCII unencoded or in UTF-8 if non-ASCII characters are present but unfortunately UTF-8 is not yet a MIME standard and not all email clients are supporting it. The optimal method would be to determine the best charset by analyzing the actual characters. That would require much more work (exept if an open source library already exists for this). However there is nothing to stop somebody to add a detection algorithm for a specific charset.
The current algorithm works correctly if only ASCII characters are added to an existing subject.
If the new value is ASCII only, then it doesn't apply any encoding to the subject header. (This is provided by MimeMessage.setSubject()).
Possible enhancement: under java 1.4 java.nio the system can determine if the suggested charset fits or not (if there is untranslatable characters). If the charset doesn't fit the new value, it can fall back to UTF-8.

param
message the message of which subject is changed
param
newValue the new (unencoded) value of the subject. It must not be null.
throws
MessagingException - according to the JavaMail doc most likely this is never thrown

        String rawSubject = message.getHeader(RFC2822Headers.SUBJECT, null);
        String mimeCharset = determineMailHeaderEncodingCharset(rawSubject);
        if (mimeCharset == null) { // most likely ASCII
            // it uses the system charset or the value of the
            // mail.mime.charset property if set  
            message.setSubject(newValue);
            return;
        } else { // original charset determined 
            String javaCharset = javax.mail.internet.MimeUtility.javaCharset(mimeCharset);
            try {
                message.setSubject(newValue, javaCharset);
            } catch (MessagingException e) {
                // known, but unsupported encoding
                // this should be logged, the admin may setup a more i18n
                // capable JRE, but the log API cannot be accessed from here  
                //if (charset != null) log(charset + 
                //      " charset unsupported by the JRE, email subject may be damaged");
                message.setSubject(newValue); // recover
            }
        }
    
private voidcheckInitParameters(java.lang.String[] allowedArray)
Checks if there are unallowed init parameters specified in the configuration file against the String[] allowedInitParameters.

        // if null then no check is requested
        if (allowedArray == null) {
            return;
        }
        
        Collection allowed = new HashSet();
        Collection bad = new ArrayList();
        
        for (int i = 0; i < allowedArray.length; i++) {
            allowed.add(allowedArray[i]);
        }
        
        Iterator iterator = getInitParameterNames();
        while (iterator.hasNext()) {
            String parameter = (String) iterator.next();
            if (!allowed.contains(parameter)) {
                bad.add(parameter);
            }
        }
        
        if (bad.size() > 0) {
            throw new MessagingException("Unexpected init parameters found: "
                                         + arrayToString(bad.toArray()));
        }
    
private static java.lang.StringdetermineMailHeaderEncodingCharset(java.lang.String rawText)
It attempts to determine the charset used to encode an "unstructured" RFC 822 header (like Subject). The encoding is specified in RFC 2047. If it cannot determine or the the text is not encoded then it returns null. Here is an example raw text: Subject: =?iso-8859-2?Q?leg=FAjabb_pr=F3ba_l=F5elemmel?=

param
rawText the raw (not decoded) value of the header. Null means that the header was not present (in this case it always return null).
return
the MIME charset name or null if no encoding applied

        if (rawText == null) return null;
        int iEncodingPrefix = rawText.indexOf("=?");
        if (iEncodingPrefix == -1) return null;
        int iCharsetBegin = iEncodingPrefix + 2; 
        int iSecondQuestionMark = rawText.indexOf('?", iCharsetBegin);
        if (iSecondQuestionMark == -1) return null;
        // safety checks
        if (iSecondQuestionMark == iCharsetBegin) return null; // empty charset? impossible
        int iThirdQuestionMark = rawText.indexOf('?", iSecondQuestionMark + 1);
        if (iThirdQuestionMark == -1) return null; // there must be one after encoding
        if (-1 == rawText.indexOf("?=", iThirdQuestionMark + 1)) return null; // closing tag
        String mimeCharset = rawText.substring(iCharsetBegin, iSecondQuestionMark);
        return mimeCharset;
    
protected java.lang.String[]getAllowedInitParameters()
Gets the expected init parameters.

return
null meaning no check

        return null;
    
protected intgetAttachmentType(org.apache.mailet.Mail originalMail)
Gets the attachment property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getAttachmentType()}

        return (isStatic()) ? this.attachmentType : getAttachmentType();
    
protected intgetAttachmentType()
Gets the attachment property. May return one of the following values to indicate how to attach the original message to the new message:
  • BODY : original message body is attached as plain text to the new message
  • HEADS : original message headers are attached as plain text to the new message
  • ALL : original is attached as plain text with all headers
  • MESSAGE : original message is attached as type message/rfc822, a complete mail message.
  • NONE : original is not attached
Is a "getX()" method.

return
the attachment init parameter, or NONE if missing

        return getTypeCode(getInitParameter("attachment","none"));
    
protected booleangetFakeDomainCheck()
Gets the fakeDomainCheck property. Return true to check if the sender domain is valid. Is a "getX()" method.

return
the fakeDomainCheck init parameter, or true if missing

        return new Boolean(getInitParameter("fakeDomainCheck")).booleanValue();
    
protected booleangetFakeDomainCheck(org.apache.mailet.Mail originalMail)
Gets the fakeDomainCheck property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getFakeDomainCheck()}

        return (isStatic()) ? this.fakeDomainCheck : getFakeDomainCheck();
    
protected intgetInLineType()
Gets the inline property. May return one of the following values to indicate how to append the original message to build the new message:
  • UNALTERED : original message is the new message body
  • BODY : original message body is appended to the new message
  • HEADS : original message headers are appended to the new message
  • ALL : original is appended with all headers
  • NONE : original is not appended
Is a "getX()" method.

return
the inline init parameter, or UNALTERED if missing

        return getTypeCode(getInitParameter("inline","unaltered"));
    
protected intgetInLineType(org.apache.mailet.Mail originalMail)
Gets the inline property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getInLineType()}

        return (isStatic()) ? this.inLineType : getInLineType();
    
protected java.lang.StringgetMessage()
Gets the message property. Returns a message to which the original message can be attached/appended to build the new message. Is a "getX()" method.

return
the message init parameter or an empty string if missing

        return getInitParameter("message","");
    
protected java.lang.StringgetMessage(org.apache.mailet.Mail originalMail)
Gets the message property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getMessage()}

        return (isStatic()) ? this.messageText : getMessage();
    
private java.lang.StringgetMessageBody(javax.mail.internet.MimeMessage message)
Utility method for obtaining a string representation of a Message's body

        java.io.ByteArrayOutputStream bodyOs = new java.io.ByteArrayOutputStream();
        MimeMessageUtil.writeMessageBodyTo(message,bodyOs);
        return bodyOs.toString();
    
protected java.lang.StringgetMessageHeaders(javax.mail.internet.MimeMessage message)
Utility method for obtaining a string representation of a Message's headers

        Enumeration heads = message.getAllHeaderLines();
        StringBuffer headBuffer = new StringBuffer(1024);
        while(heads.hasMoreElements()) {
            headBuffer.append(heads.nextElement().toString()).append("\r\n");
        }
        return headBuffer.toString();
    
protected booleangetPassThrough()
Gets the passThrough property. Return true to allow the original message to continue through the processor, false to GHOST it. Is a "getX()" method.

return
the passThrough init parameter, or false if missing

        return new Boolean(getInitParameter("passThrough")).booleanValue();
    
protected booleangetPassThrough(org.apache.mailet.Mail originalMail)
Gets the passThrough property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getPassThrough()}

        return (isStatic()) ? this.passThrough : getPassThrough();
    
protected java.util.CollectiongetRecipients()
Gets the recipients property. Returns the collection of recipients of the new message, or null if no change is requested. Is a "getX()" method.

return
the recipients init parameter or the postmaster address or SpecialAddress.SENDER or SpecialAddress.FROM or SpecialAddress.REPLY_TO or SpecialAddress.REVERSE_PATH or SpecialAddress.UNALTERED or SpecialAddress.RECIPIENTS or null if missing

        Collection newRecipients = new HashSet();
        String addressList = getInitParameter("recipients");
        
        // if nothing was specified, return <CODE>null</CODE> meaning no change
        if (addressList == null) {
            return null;
        }

        try {
            InternetAddress[] iaarray = InternetAddress.parse(addressList, false);
            for (int i = 0; i < iaarray.length; i++) {
                String addressString = iaarray[i].getAddress();
                MailAddress specialAddress = getSpecialAddress(addressString,
                new String[] {"postmaster", "sender", "from", "replyTo", "reversePath", "unaltered", "recipients", "to", "null"});
                if (specialAddress != null) {
                    newRecipients.add(specialAddress);
                } else {
                    newRecipients.add(new MailAddress(iaarray[i]));
                }
            }
        } catch (Exception e) {
            throw new MessagingException("Exception thrown in getRecipients() parsing: " + addressList, e);
        }
        if (newRecipients.size() == 0) {
            throw new MessagingException("Failed to initialize \"recipients\" list; empty <recipients> init parameter found.");
        }

        return newRecipients;
    
protected java.util.CollectiongetRecipients(org.apache.mailet.Mail originalMail)
Gets the recipients property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #replaceMailAddresses} on {@link #getRecipients()},

        Collection recipients = (isStatic()) ? this.recipients : getRecipients();
        if (recipients != null) {
            if (recipients.size() == 1 && (recipients.contains(SpecialAddress.UNALTERED) || recipients.contains(SpecialAddress.RECIPIENTS))) {
                recipients = null;
            } else {
                recipients = replaceMailAddresses(originalMail, recipients);
            }
        }
        return recipients;
    
protected org.apache.mailet.MailAddressgetReplyTo()
Gets the replyto property. Returns the Reply-To address of the new message, or null if no change is requested. Is a "getX()" method.

return
the replyto init parameter or the postmaster address or SpecialAddress.SENDER or SpecialAddress.UNALTERED or SpecialAddress.NULL or null if missing

        String addressString = getInitParameter("replyTo",getInitParameter("replyto"));

        if(addressString != null) {
            MailAddress specialAddress = getSpecialAddress(addressString,
                                            new String[] {"postmaster", "sender", "null", "unaltered"});
            if (specialAddress != null) {
                return specialAddress;
            }

            try {
                return new MailAddress(addressString);
            } catch(Exception e) {
                throw new MessagingException("Exception thrown in getReplyTo() parsing: " + addressString, e);
            }
        }

        return null;
    
protected org.apache.mailet.MailAddressgetReplyTo(org.apache.mailet.Mail originalMail)
Gets the replyTo property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getReplyTo()} replacing SpecialAddress.UNALTERED if applicable with null and SpecialAddress.SENDER with the original mail sender

        MailAddress replyTo = (isStatic()) ? this.replyTo : getReplyTo();
        if (replyTo != null) {
            if (replyTo == SpecialAddress.UNALTERED) {
                replyTo = null;
            } else if (replyTo == SpecialAddress.SENDER) {
                replyTo = originalMail.getSender();
            }
        }
        return replyTo;
    
protected org.apache.mailet.MailAddressgetReversePath()
Gets the reversePath property. Returns the reverse-path of the new message, or null if no change is requested. Is a "getX()" method.

return
the reversePath init parameter or the postmaster address or SpecialAddress.SENDER or SpecialAddress.NULL or SpecialAddress.UNALTERED or null if missing

        String addressString = getInitParameter("reversePath");
        if(addressString != null) {
            MailAddress specialAddress = getSpecialAddress(addressString,
                                            new String[] {"postmaster", "sender", "null", "unaltered"});
            if (specialAddress != null) {
                return specialAddress;
            }

            try {
                return new MailAddress(addressString);
            } catch(Exception e) {
                throw new MessagingException("Exception thrown in getReversePath() parsing: " + addressString, e);
            }
        }

        return null;
    
protected org.apache.mailet.MailAddressgetReversePath(org.apache.mailet.Mail originalMail)
Gets the reversePath property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getReversePath()}, replacing SpecialAddress.SENDER if applicable with null, replacing SpecialAddress.UNALTERED and SpecialAddress.REVERSE_PATH if applicable with null, but not replacing SpecialAddress.NULL that will be handled by {@link #setReversePath}

        MailAddress reversePath = (isStatic()) ? this.reversePath : getReversePath();
        if (reversePath != null) {
            if (reversePath == SpecialAddress.UNALTERED || reversePath == SpecialAddress.REVERSE_PATH) {
                reversePath = null;
            }
            else if (reversePath == SpecialAddress.SENDER) {
                reversePath = null;
            }
        }
        return reversePath;
    
protected org.apache.mailet.MailAddressgetSender()
Gets the sender property. Returns the new sender as a MailAddress, or null if no change is requested. Is a "getX()" method.

return
the sender init parameter or the postmaster address or SpecialAddress.SENDER or SpecialAddress.UNALTERED or null if missing

        String addressString = getInitParameter("sender");
        if(addressString != null) {
            MailAddress specialAddress = getSpecialAddress(addressString,
                                            new String[] {"postmaster", "sender", "unaltered"});
            if (specialAddress != null) {
                return specialAddress;
            }

            try {
                return new MailAddress(addressString);
            } catch(Exception e) {
                throw new MessagingException("Exception thrown in getSender() parsing: " + addressString, e);
            }
        }

        return null;
    
protected org.apache.mailet.MailAddressgetSender(org.apache.mailet.Mail originalMail)
Gets the sender property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getSender()} replacing SpecialAddress.UNALTERED and SpecialAddress.SENDER if applicable with null

        MailAddress sender = (isStatic()) ? this.sender : getSender();
        if (sender != null) {
            if (sender == SpecialAddress.UNALTERED || sender == SpecialAddress.SENDER) {
                sender = null;
            }
        }
        return sender;
    
protected final org.apache.mailet.MailAddressgetSpecialAddress(java.lang.String addressString, java.lang.String[] allowedSpecials)
Returns the {@link SpecialAddress} that corresponds to an init parameter value. The init parameter value is checked against a String[] of allowed values. The checks are case insensitive.

param
addressString the string to check if is a special address
param
allowedSpecials a String[] with the allowed special addresses
return
a SpecialAddress if found, null if not found or addressString is null
throws
MessagingException if is a special address not in the allowedSpecials array

        if (addressString == null) {
            return null;
        }

        addressString = addressString.toLowerCase(Locale.US);
        addressString = addressString.trim();

        MailAddress specialAddress = null;

        if(addressString.compareTo("postmaster") == 0) {
            specialAddress = getMailetContext().getPostmaster();
        }
        if(addressString.compareTo("sender") == 0) {
            specialAddress = SpecialAddress.SENDER;
        }
        if(addressString.compareTo("reversepath") == 0) {
            specialAddress = SpecialAddress.REVERSE_PATH;
        }
        if(addressString.compareTo("from") == 0) {
            specialAddress = SpecialAddress.FROM;
        }
        if(addressString.compareTo("replyto") == 0) {
            specialAddress = SpecialAddress.REPLY_TO;
        }
        if(addressString.compareTo("to") == 0) {
            specialAddress = SpecialAddress.TO;
        }
        if(addressString.compareTo("recipients") == 0) {
            specialAddress = SpecialAddress.RECIPIENTS;
        }
        if(addressString.compareTo("delete") == 0) {
            specialAddress = SpecialAddress.DELETE;
        }
        if(addressString.compareTo("unaltered") == 0) {
            specialAddress = SpecialAddress.UNALTERED;
        }
        if(addressString.compareTo("null") == 0) {
            specialAddress = SpecialAddress.NULL;
        }

        // if is a special address, must be in the allowedSpecials array
        if (specialAddress != null) {
            // check if is an allowed special
            boolean allowed = false;
            for (int i = 0; i < allowedSpecials.length; i++) {
                String allowedSpecial = allowedSpecials[i];
                allowedSpecial = allowedSpecial.toLowerCase(Locale.US);
                allowedSpecial = allowedSpecial.trim();
                if(addressString.compareTo(allowedSpecial) == 0) {
                    allowed = true;
                    break;
                }
            }
            if (!allowed) {
                throw new MessagingException("Special (\"magic\") address found not allowed: " + addressString +
                                             ", allowed values are \"" + arrayToString(allowedSpecials) + "\"");
            }
        }

        return specialAddress;
    
protected java.lang.StringgetSubject()
Gets the subject property. Returns a string for the new message subject. Is a "getX()" method.

return
the subject init parameter or null if missing

        return getInitParameter("subject");
    
protected java.lang.StringgetSubject(org.apache.mailet.Mail originalMail)
Gets the subject property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getSubject()}

        return (isStatic()) ? this.subject : getSubject();
    
protected java.lang.StringgetSubjectPrefix()
Gets the prefix property. Returns a prefix for the new message subject. Is a "getX()" method.

return
the prefix init parameter or an empty string if missing

        return getInitParameter("prefix");
    
protected java.lang.StringgetSubjectPrefix(org.apache.mailet.Mail originalMail)
Gets the subjectPrefix property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #getSubjectPrefix()}

        return (isStatic()) ? this.subjectPrefix : getSubjectPrefix();
    
protected javax.mail.internet.InternetAddress[]getTo()
Gets the to property. Returns the "To:" recipients of the new message. or null if no change is requested. Is a "getX()" method.

return
the to init parameter or the postmaster address or SpecialAddress.SENDER or SpecialAddress.REVERSE_PATH or SpecialAddress.FROM or SpecialAddress.REPLY_TO or SpecialAddress.UNALTERED or SpecialAddress.TO or null if missing

        InternetAddress[] iaarray = null;
        String addressList = getInitParameter("to");
        
        // if nothing was specified, return null meaning no change
        if (addressList == null) {
            return null;
        }

        try {
            iaarray = InternetAddress.parse(addressList, false);
            for(int i = 0; i < iaarray.length; ++i) {
                String addressString = iaarray[i].getAddress();
                MailAddress specialAddress = getSpecialAddress(addressString,
                                                new String[] {"postmaster", "sender", "from", "replyTo", "reversePath", "unaltered", "recipients", "to", "null"});
                if (specialAddress != null) {
                    iaarray[i] = specialAddress.toInternetAddress();
                }
            }
        } catch (Exception e) {
            throw new MessagingException("Exception thrown in getTo() parsing: " + addressList, e);
        }
        if (iaarray.length == 0) {
            throw new MessagingException("Failed to initialize \"to\" list; empty <to> init parameter found.");
        }

        return iaarray;
    
protected javax.mail.internet.InternetAddress[]getTo(org.apache.mailet.Mail originalMail)
Gets the to property, built dynamically using the original Mail object. Its outcome will be the the value the TO: header will be set to, that could be different from the real recipient (see {@link #getRecipients}). Is a "getX(Mail)" method.

return
{@link #replaceInternetAddresses} on {@link #getRecipients()},

        InternetAddress[] apparentlyTo = (isStatic()) ? this.apparentlyTo : getTo();
        if (apparentlyTo != null) {
            if (   apparentlyTo.length == 1
                && (   apparentlyTo[0].equals(SpecialAddress.UNALTERED.toInternetAddress())
                    || apparentlyTo[0].equals(SpecialAddress.TO.toInternetAddress())
                    )) {
                apparentlyTo = null;
            } else {
                Collection toList = new ArrayList(apparentlyTo.length);
                for (int i = 0; i < apparentlyTo.length; i++) {
                    toList.add(apparentlyTo[i]);
                }
                /* IMPORTANT: setTo() treats null differently from a zero length array,
                  so it's ok to get a zero length array from replaceSpecialAddresses
                 */
                apparentlyTo = (InternetAddress[]) replaceInternetAddresses(originalMail, toList).toArray(new InternetAddress[0]);
            }
        }
        
        return apparentlyTo;
    
protected intgetTypeCode(java.lang.String param)
A private method to convert types from string to int.

param
param the string type
return
the corresponding int enumeration

        param = param.toLowerCase(Locale.US);
        if(param.compareTo("unaltered") == 0) {
            return UNALTERED;
        }
        if(param.compareTo("heads") == 0) {
            return HEADS;
        }
        if(param.compareTo("body") == 0) {
            return BODY;
        }
        if(param.compareTo("all") == 0) {
            return ALL;
        }
        if(param.compareTo("none") == 0) {
            return NONE;
        }
        if(param.compareTo("message") == 0) {
            return MESSAGE;
        }
        return NONE;
    
public voidinit()
Mailet initialization routine. Will setup static values for each "x" initialization parameter in config.xml, using getX(), if {@link #isStatic()} returns true.

        isDebug = new Boolean(getInitParameter("debug","false")).booleanValue();

        isStatic = new Boolean(getInitParameter("static","false")).booleanValue();

        if (isDebug) {
            log("Initializing");
        }
        
        // check that all init parameters have been declared in allowedInitParameters
        checkInitParameters(getAllowedInitParameters());
        
        if(isStatic()) {
            passThrough         = getPassThrough();
            fakeDomainCheck     = getFakeDomainCheck();
            attachmentType      = getAttachmentType();
            inLineType          = getInLineType();
            messageText         = getMessage();
            recipients          = getRecipients();
            replyTo             = getReplyTo();
            reversePath         = getReversePath();
            sender              = getSender();
            subject             = getSubject();
            subjectPrefix       = getSubjectPrefix();
            apparentlyTo        = getTo();
            attachError         = attachError();
            isReply             = isReply();
            if (isDebug) {
                StringBuffer logBuffer =
                    new StringBuffer(1024)
                            .append("static")
                            .append(", passThrough=").append(passThrough)
                            .append(", fakeDomainCheck=").append(fakeDomainCheck)
                            .append(", sender=").append(sender)
                            .append(", replyTo=").append(replyTo)
                            .append(", reversePath=").append(reversePath)
                            .append(", message=").append(messageText)
                            .append(", recipients=").append(arrayToString(recipients == null ? null : recipients.toArray()))
                            .append(", subject=").append(subject)
                            .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());
            }
        }
    
protected booleanisReply()
Gets the isReply property. 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
the isReply init parameter; false if missing

        return new Boolean(getInitParameter("isReply")).booleanValue();
    
protected booleanisReply(org.apache.mailet.Mail originalMail)
Gets the isReply property, built dynamically using the original Mail object. Is a "getX(Mail)" method.

return
{@link #isReply()}

        return (isStatic()) ? this.isReply : isReply();
    
protected booleanisStatic()

Gets the static property.

Return true to reduce calls to getTo, getSender, getRecipients, getReplyTo, getReversePath amd getMessage where these values don't change (eg hard coded, or got at startup from the mailet config); 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.

It is now (from version 2.2) somehow obsolete, as should be always true because the "good practice" is to use "getX()" methods statically, and use instead "getX(Mail)" methods for dynamic situations. A false value is now meaningful only for subclasses of {@link Redirect} older than version 2.2 that were relying on this.

Is a "getX()" method.

return
true, as normally "getX()" methods shouls be static


    /* ******************************************************************** */
    /* ****************** Begin of getX and setX methods ****************** */
    /* ******************************************************************** */

                                                                                                                                      
       
        return true;
    
private java.lang.StringnewName(org.apache.mailet.Mail mail)
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

  // Used to generate new mail names

                                  
          
        String oldName = mail.getName();
        
        // Checking if the original mail name is too long, perhaps because of a
        // loop caused by a configuration error.
        // it could cause a "null pointer exception" in AvalonMailRepository much
        // harder to understand.
        if (oldName.length() > 76) {
            int count = 0;
            int index = 0;
            while ((index = oldName.indexOf('!", index + 1)) >= 0) {
                count++;
            }
            // It looks like a configuration loop. It's better to stop.
            if (count > 7) {
                throw new MessagingException("Unable to create a new message name: too long."
                                             + " Possible loop in config.xml.");
            }
            else {
                oldName = oldName.substring(0, 76);
            }
        }
        
        StringBuffer nameBuffer =
                                 new StringBuffer(64)
                                 .append(oldName)
                                 .append("-!")
                                 .append(random.nextInt(1048576));
        return nameBuffer.toString();
    
protected java.util.CollectionreplaceInternetAddresses(org.apache.mailet.Mail mail, java.util.Collection list)
Returns a new Collection built over list replacing special addresses with real InternetAddress-es.
Manages SpecialAddress.SENDER, SpecialAddress.REVERSE_PATH, SpecialAddress.FROM, SpecialAddress.REPLY_TO, SpecialAddress.RECIPIENTS, SpecialAddress.TO, SpecialAddress.NULL and SpecialAddress.UNALTERED.
SpecialAddress.RECIPIENTS is made equivalent to SpecialAddress.TO.
SpecialAddress.FROM uses the From header if available, otherwise the Sender header if available, otherwise the return-path.
SpecialAddress.REPLY_TO uses the ReplyTo header if available, otherwise the From header if available, otherwise the Sender header if available, otherwise the return-path.
SpecialAddress.UNALTERED is ignored.
Any other address is not replaced.

        Collection newList = new HashSet(list.size());
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            InternetAddress internetAddress = (InternetAddress) iterator.next();
            MailAddress mailAddress = new MailAddress(internetAddress);
            if (!mailAddress.getHost().equalsIgnoreCase("address.marker")) {
                newList.add(internetAddress);
            } else if (internetAddress.equals(SpecialAddress.SENDER.toInternetAddress())) {
                MailAddress sender = mail.getSender();
                if (sender != null) {
                    newList.add(sender.toInternetAddress());
                }
            } else if (internetAddress.equals(SpecialAddress.REVERSE_PATH.toInternetAddress())) {
                MailAddress reversePath = mail.getSender();
                if (reversePath != null) {
                    newList.add(reversePath.toInternetAddress());
                }
            } else if (internetAddress.equals(SpecialAddress.FROM.toInternetAddress())) {
                try {
                    InternetAddress[] fromArray = (InternetAddress[]) mail.getMessage().getFrom();
                    if (fromArray != null) {
                        for (int i = 0; i < fromArray.length; i++) {
                            newList.add(fromArray[i]);
                        }
                    } else {
                        MailAddress reversePath = mail.getSender();
                        if (reversePath != null) {
                            newList.add(reversePath.toInternetAddress());
                        }
                    }
                } catch (MessagingException me) {
                    log("Unable to parse the \"FROM\" header in the original message; ignoring.");
                }
            } else if (internetAddress.equals(SpecialAddress.REPLY_TO.toInternetAddress())) {
                try {
                    InternetAddress[] replyToArray = (InternetAddress[]) mail.getMessage().getReplyTo();
                    if (replyToArray != null) {
                        for (int i = 0; i < replyToArray.length; i++) {
                            newList.add(replyToArray[i]);
                        }
                    } else {
                        MailAddress reversePath = mail.getSender();
                        if (reversePath != null) {
                            newList.add(reversePath.toInternetAddress());
                        }
                    }
                } catch (MessagingException me) {
                    log("Unable to parse the \"REPLY_TO\" header in the original message; ignoring.");
                }
            } else if (internetAddress.equals(SpecialAddress.TO.toInternetAddress())
                       || internetAddress.equals(SpecialAddress.RECIPIENTS.toInternetAddress())) {
                try {
                    String[] toHeaders = mail.getMessage().getHeader(RFC2822Headers.TO);
                    if (toHeaders != null) {
                        for (int i = 0; i < toHeaders.length; i++) {
                            try {
                                InternetAddress[] originalToInternetAddresses = InternetAddress.parse(toHeaders[i], false);
                                for (int j = 0; j < originalToInternetAddresses.length; j++) {
                                    newList.add(originalToInternetAddresses[j]);
                                }
                            } catch (MessagingException ae) {
                                log("Unable to parse a \"TO\" header address in the original message: " + toHeaders[i] + "; ignoring.");
                            }
                        }
                    }
                } catch (MessagingException ae) {
                    log("Unable to parse the \"TO\" header  in the original message; ignoring.");
                }
            } else if (internetAddress.equals(SpecialAddress.UNALTERED.toInternetAddress())) {
                continue;
            } else if (internetAddress.equals(SpecialAddress.NULL.toInternetAddress())) {
                continue;
            } else {
                newList.add(internetAddress);
            }
        }
        return newList;
    
protected java.util.CollectionreplaceMailAddresses(org.apache.mailet.Mail mail, java.util.Collection list)
Returns a new Collection built over list replacing special addresses with real MailAddress-es.
Manages SpecialAddress.SENDER, SpecialAddress.REVERSE_PATH, SpecialAddress.FROM, SpecialAddress.REPLY_TO, SpecialAddress.RECIPIENTS, SpecialAddress.TO, SpecialAddress.NULL and SpecialAddress.UNALTERED.
SpecialAddress.FROM is made equivalent to SpecialAddress.SENDER; SpecialAddress.TO is made equivalent to SpecialAddress.RECIPIENTS.
SpecialAddress.REPLY_TO uses the ReplyTo header if available, otherwise the From header if available, otherwise the Sender header if available, otherwise the return-path.
SpecialAddress.NULL and SpecialAddress.UNALTERED are ignored.
Any other address is not replaced.

        Collection newList = new HashSet(list.size());
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            MailAddress mailAddress = (MailAddress) iterator.next();
            if (!mailAddress.getHost().equalsIgnoreCase("address.marker")) {
                newList.add(mailAddress);
            } else if (mailAddress == SpecialAddress.SENDER || mailAddress == SpecialAddress.FROM) {
                MailAddress sender = mail.getSender();
                if (sender != null) {
                    newList.add(sender);
                }
            } else if (mailAddress == SpecialAddress.REPLY_TO) {
                int parsedAddressCount = 0;
                try {
                    InternetAddress[] replyToArray = (InternetAddress[]) mail.getMessage().getReplyTo();
                    if (replyToArray != null) {
                        for (int i = 0; i < replyToArray.length; i++) {
                            try {
                                newList.add(new MailAddress(replyToArray[i]));
                                parsedAddressCount++;
                            } catch (ParseException pe) {
                                log("Unable to parse a \"REPLY_TO\" header address in the original message: " + replyToArray[i] + "; ignoring.");
                            }
                        }
                    }
                } catch (MessagingException ae) {
                    log("Unable to parse the \"REPLY_TO\" header in the original message; ignoring.");
                }
                // no address was parsed?
                if (parsedAddressCount == 0) {
                    MailAddress sender = mail.getSender();
                    if (sender != null) {
                        newList.add(sender);
                    }
                }
            } else if (mailAddress == SpecialAddress.REVERSE_PATH) {
                MailAddress reversePath = mail.getSender();
                if (reversePath != null) {
                    newList.add(reversePath);
                }
            } else if (mailAddress == SpecialAddress.RECIPIENTS || mailAddress == SpecialAddress.TO) {
                newList.addAll(mail.getRecipients());
            } else if (mailAddress == SpecialAddress.UNALTERED) {
                continue;
            } else if (mailAddress == SpecialAddress.NULL) {
                continue;
            } else {
                newList.add(mailAddress);
            }
        }
        return newList;
    
protected final booleansenderDomainIsValid(org.apache.mailet.Mail mail)

Checks if a sender domain of mail is valid.

If we do not do this check, and someone uses a redirection mailet in a processor initiated by SenderInFakeDomain, then a fake sender domain will cause an infinite loop (the forwarded e-mail still appears to come from a fake domain).
Although this can be viewed as a configuration error, the consequences of such a mis-configuration are severe enough to warrant protecting against the infinite loop.

This check can be skipped if {@link #getFakeDomainCheck(Mail)} returns true.

param
mail the mail object to check
return
true if the if the sender is null or {@link org.apache.mailet.MailetContext#getMailServers} returns true for the sender host part

        if (getFakeDomainCheck(mail)) {
            return mail.getSender() == null || getMailetContext().getMailServers(mail.getSender().getHost()).size() != 0;
        } else return true;
    
public voidservice(org.apache.mailet.Mail originalMail)
Service does the hard work,and redirects the originalMail in the form specified.

param
originalMail the mail to process and redirect
throws
MessagingException if a problem arises formulating the redirected mail


        boolean keepMessageId = false;

        // duplicates the Mail object, to be able to modify the new mail keeping the original untouched
        MailImpl newMail = new MailImpl(originalMail,newName(originalMail));
        try {
            // We don't need to use the original Remote Address and Host,
            // and doing so would likely cause a loop with spam detecting
            // matchers.
            try {
                newMail.setRemoteAddr(java.net.InetAddress.getLocalHost().getHostAddress());
                newMail.setRemoteHost(java.net.InetAddress.getLocalHost().getHostName());
            } catch (java.net.UnknownHostException _) {
                newMail.setRemoteAddr("127.0.0.1");
                newMail.setRemoteHost("localhost");
            }
    
            if (isDebug) {
                log("New mail - sender: " + newMail.getSender()
                           + ", recipients: " + arrayToString(newMail.getRecipients().toArray())
                           + ", name: " + newMail.getName()
                           + ", remoteHost: " + newMail.getRemoteHost()
                           + ", remoteAddr: " + newMail.getRemoteAddr()
                           + ", state: " + newMail.getState()
                           + ", lastUpdated: " + newMail.getLastUpdated()
                           + ", errorMessage: " + newMail.getErrorMessage());
            }
    
            //Create the message
            if(getInLineType(originalMail) != UNALTERED) {
                if (isDebug) {
                    log("Alter message");
                }
                newMail.setMessage(new MimeMessage(Session.getDefaultInstance(System.getProperties(),
                                                                   null)));
    
                // handle the new message if altered
                buildAlteredMessage(newMail, originalMail);
    
            } else {
                // if we need the original, create a copy of this message to redirect
                if (getPassThrough(originalMail)) {
                    newMail.setMessage(new MimeMessage(originalMail.getMessage()) {
                        protected void updateHeaders() throws MessagingException {
                            if (getMessageID() == null) super.updateHeaders();
                            else {
                                modified = false;
                            }
                        }
                    });
                }
                if (isDebug) {
                    log("Message resent unaltered.");
                }
                keepMessageId = true;
            }
    
            //Set additional headers
    
            setRecipients(newMail, getRecipients(originalMail), originalMail);
    
            setTo(newMail, getTo(originalMail), originalMail);
    
            setSubjectPrefix(newMail, getSubjectPrefix(originalMail), originalMail);
    
            if(newMail.getMessage().getHeader(RFC2822Headers.DATE) == null) {
                newMail.getMessage().setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new Date()));
            }
    
            setReplyTo(newMail, getReplyTo(originalMail), originalMail);
    
            setReversePath(newMail, getReversePath(originalMail), originalMail);
    
            setSender(newMail, getSender(originalMail), originalMail);
    
            setIsReply(newMail, isReply(originalMail), originalMail);
    
            newMail.getMessage().saveChanges();
    
            if (keepMessageId) {
                setMessageId(newMail, originalMail);
            }
    
            if (senderDomainIsValid(newMail)) {
                //Send it off...
                getMailetContext().sendMail(newMail);
            } else {
                StringBuffer logBuffer = new StringBuffer(256)
                                        .append(getMailetName())
                                        .append(" mailet cannot forward ")
                                        .append(originalMail.getName())
                                        .append(". Invalid sender domain for ")
                                        .append(newMail.getSender())
                                        .append(". Consider using the Resend mailet ")
                                        .append("using a different sender.");
                throw new MessagingException(logBuffer.toString());
            }
    
        } finally {
            newMail.dispose();
        }
        
        if(!getPassThrough(originalMail)) {
            originalMail.setState(Mail.GHOST);
        }
    
protected voidsetIsReply(org.apache.mailet.Mail newMail, boolean isReply, org.apache.mailet.Mail originalMail)
Sets the "In-Reply-To:" header of newMail to the "Message-Id:" of originalMail, if isReply is true.

        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);
                }
            }
        }
    
private voidsetMessageId(org.apache.mailet.Mail newMail, org.apache.mailet.Mail originalMail)
Sets the message id of originalMail into newMail.

        String messageId = originalMail.getMessage().getMessageID();
        if (messageId != null) {
            newMail.getMessage().setHeader(RFC2822Headers.MESSAGE_ID, messageId);
            if (isDebug) {
                log("MESSAGE_ID restored to: " + messageId);
            }
        }
    
protected voidsetRecipients(org.apache.mailet.Mail newMail, java.util.Collection recipients, org.apache.mailet.Mail originalMail)
Sets the recipients of newMail to recipients. If the requested value is null does nothing. Is a "setX(Mail, Tx, Mail)" method.

        if (recipients != null) {
            newMail.setRecipients(recipients);
            if (isDebug) {
                log("recipients set to: " + arrayToString(recipients.toArray()));
            }
        }
    
protected voidsetReplyTo(org.apache.mailet.Mail newMail, org.apache.mailet.MailAddress replyTo, org.apache.mailet.Mail originalMail)

Sets the "Reply-To:" header of newMail to replyTo.

If the requested value is SpecialAddress.NULL will remove the "Reply-To:" header. If the requested value is null does nothing.

Is a "setX(Mail, Tx, Mail)" method.

        if(replyTo != null) {
            InternetAddress[] iart = null;
            if (replyTo != SpecialAddress.NULL) {
                iart = new InternetAddress[1];
                iart[0] = replyTo.toInternetAddress();
            }
            
            // Note: if iart is null will remove the header
            newMail.getMessage().setReplyTo(iart);
            
            if (isDebug) {
                log("replyTo set to: " + replyTo);
            }
        }
    
protected voidsetReversePath(org.apache.james.core.MailImpl newMail, org.apache.mailet.MailAddress reversePath, org.apache.mailet.Mail originalMail)
Sets the "reverse-path" of newMail to reversePath. If the requested value is SpecialAddress.NULL sets it to "<>". If the requested value is null does nothing. Is a "setX(Mail, Tx, Mail)" method.

        if(reversePath != null) {
            if (reversePath == SpecialAddress.NULL) {
                reversePath = null;
            }
            newMail.setSender(reversePath);
            if (isDebug) {
                log("reversePath set to: " + reversePath);
            }
        }
    
protected voidsetSender(org.apache.mailet.Mail newMail, org.apache.mailet.MailAddress sender, org.apache.mailet.Mail originalMail)
Sets the "From:" header of newMail to sender. If the requested value is null does nothing. Is a "setX(Mail, Tx, Mail)" method.

        if (sender != null) {
            newMail.getMessage().setFrom(sender.toInternetAddress());
            
            if (isDebug) {
                log("sender set to: " + sender);
            }
        }
    
protected voidsetSubjectPrefix(org.apache.mailet.Mail newMail, java.lang.String subjectPrefix, org.apache.mailet.Mail originalMail)
Builds the subject of newMail appending the subject of originalMail to subjectPrefix. Is a "setX(Mail, Tx, Mail)" method.

        String subject = getSubject(originalMail);
        if ((subjectPrefix != null && subjectPrefix.length() > 0) || subject != null) {
            if (subject == null) {
                subject = originalMail.getMessage().getSubject();
            } else {
                // replacing the subject
                if (isDebug) {
                    log("subject set to: " + subject);
                }
            }
            // Was null in original?
            if (subject == null) {
                subject = "";
            }
            
            if (subjectPrefix != null) {
                subject = subjectPrefix + subject;
                // adding a prefix
                if (isDebug) {
                    log("subjectPrefix set to: " + subjectPrefix);
                }
            }
//            newMail.getMessage().setSubject(subject);
            changeSubject(newMail.getMessage(), subject);
        }
    
protected voidsetTo(org.apache.mailet.Mail newMail, javax.mail.internet.InternetAddress[] to, org.apache.mailet.Mail originalMail)
Sets the "To:" header of newMail to to. If the requested value is null does nothing. Is a "setX(Mail, Tx, Mail)" method.

        if (to != null) {
            newMail.getMessage().setRecipients(Message.RecipientType.TO, to);
            if (isDebug) {
                log("apparentlyTo set to: " + arrayToString(to));
            }
        }