vincenzo 2003/06/30 02:42:08 Modified: src/java/org/apache/james/transport/mailets Tag: branch_2_1_fcs AbstractNotify.java AbstractRedirect.java Bounce.java Forward.java GenericListserv.java NotifyPostmaster.java NotifySender.java Redirect.java Resend.java Log: AbstractRedirect hierarchy: 1) Enhancement and cleanup in default parameter management. 2) Throws MessagingException instead of log in case of address parsing errors. 3) Was not copying default headers in case of inline != unaltered - major fix. 4) Redirect supports <subject>. 4) Applied Hontvari Joszef's patch for supporting non-ascii characters (involves also GenericListserv). Revision Changes Path No revision No revision 1.1.2.8 +4 -4 jakarta-james/src/java/org/apache/james/transport/mailets/AbstractNotify.java Index: AbstractNotify.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/AbstractNotify.java,v retrieving revision 1.1.2.7 retrieving revision 1.1.2.8 diff -u -r1.1.2.7 -r1.1.2.8 --- AbstractNotify.java 27 Jun 2003 14:34:37 -0000 1.1.2.7 +++ AbstractNotify.java 30 Jun 2003 09:42:07 -0000 1.1.2.8 @@ -258,10 +258,10 @@ } /** - * @return null + * @return [EMAIL PROTECTED] AbstractRedirect#getSender(Mail)}, meaning the new requested sender if any */ - protected MailAddress getReturnPath() throws MessagingException { - return null; + protected MailAddress getReturnPath(Mail originalMail) throws MessagingException { + return getSender(originalMail); } /** 1.1.2.14 +169 -114 jakarta-james/src/java/org/apache/james/transport/mailets/AbstractRedirect.java Index: AbstractRedirect.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/AbstractRedirect.java,v retrieving revision 1.1.2.13 retrieving revision 1.1.2.14 diff -u -r1.1.2.13 -r1.1.2.14 --- AbstractRedirect.java 27 Jun 2003 14:34:37 -0000 1.1.2.13 +++ AbstractRedirect.java 30 Jun 2003 09:42:07 -0000 1.1.2.14 @@ -464,10 +464,12 @@ StringTokenizer st = new StringTokenizer(addressList, ",", false); while(st.hasMoreTokens()) { + String token = null; try { - newRecipients.add(new MailAddress(st.nextToken())); + token = st.nextToken(); + newRecipients.add(new MailAddress(token)); } catch(Exception e) { - log("add recipient failed in getRecipients"); + throw new MessagingException("Exception thrown in getRecipients() parsing: " + token, e); } } return newRecipients; @@ -480,12 +482,13 @@ * * @return [EMAIL PROTECTED] #getRecipients()}, * replacing <CODE>SpecialAddress.SENDER</CODE> if applicable with the original sender - * and <CODE>SpecialAddress.UNALTERED</CODE> if applicable with null + * and <CODE>SpecialAddress.UNALTERED</CODE> + * and <CODE>SpecialAddress.RECIPIENTS</CODE> if applicable with null */ protected Collection getRecipients(Mail originalMail) throws MessagingException { Collection recipients = (isStatic()) ? this.recipients : getRecipients(); if (recipients != null && recipients.size() == 1) { - if (recipients.contains(SpecialAddress.UNALTERED)) { + if (recipients.contains(SpecialAddress.UNALTERED) || recipients.contains(SpecialAddress.RECIPIENTS)) { recipients = null; } else if (recipients.contains(SpecialAddress.SENDER)) { recipients = new ArrayList(); @@ -558,7 +561,7 @@ tokenx = rec.nextToken(); iaarray[i] = new InternetAddress(tokenx); } catch(Exception e) { - log("Internet address exception in getTo()"); + throw new MessagingException("Exception thrown in getTo() parsing: " + tokenx, e); } } return iaarray; @@ -583,6 +586,7 @@ * </LI> * <LI> * If <CODE>getTo()</CODE> returns <CODE>SpecialAddress.UNALTERED</CODE> + * or <CODE>SpecialAddress.TO</CODE> * it returns the original <I>TO:</I>. * </LI> * <LI> @@ -595,7 +599,9 @@ * </UL> * * @return [EMAIL PROTECTED] #getTo()}, replacing <CODE>SpecialAddress.SENDER</CODE>, - * <CODE>SpecialAddress.SENDER</CODE> and <CODE>SpecialAddress.UNALTERED</CODE> if applicable + * <CODE>SpecialAddress.SENDER</CODE>, + * <CODE>SpecialAddress.TO</CODE>, + * and <CODE>SpecialAddress.UNALTERED</CODE> if applicable */ protected InternetAddress[] getTo(Mail originalMail) throws MessagingException { InternetAddress[] apparentlyTo = (isStatic()) ? this.apparentlyTo : getTo(); @@ -618,7 +624,8 @@ apparentlyTo = new InternetAddress[1]; apparentlyTo[0] = mailAddress.toInternetAddress(); } - } else if (apparentlyTo[0].equals(SpecialAddress.UNALTERED.toInternetAddress())) { + } else if (apparentlyTo[0].equals(SpecialAddress.UNALTERED.toInternetAddress()) + || apparentlyTo[0].equals(SpecialAddress.TO.toInternetAddress())) { apparentlyTo = (InternetAddress[]) originalMail.getMessage().getRecipients(Message.RecipientType.TO); } else if (apparentlyTo[0].equals(SpecialAddress.RETURN_PATH.toInternetAddress())) { MailAddress mailAddress = getExistingReturnPath(originalMail); @@ -683,7 +690,7 @@ try { return new MailAddress(addressString); } catch(Exception e) { - log("Parse error in getReplyTo: " + addressString); + throw new MessagingException("Exception thrown in getReplyTo() parsing: " + addressString, e); } } @@ -697,12 +704,15 @@ * * @return [EMAIL PROTECTED] #getReplyTo()} * replacing <CODE>SpecialAddress.UNALTERED</CODE> if applicable with null + * and <CODE>SpecialAddress.SENDER</CODE> with the original mail sender */ protected MailAddress getReplyTo(Mail originalMail) throws MessagingException { 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; @@ -710,25 +720,12 @@ /** * <P>Sets the "Reply-To:" header of <I>newMail</I> to <I>replyTo</I>.</P> - * <P>If the requested value is <CODE>SpecialAddress.SENDER</CODE> will use the original "From:" header; - * if this header is empty will use the original "Sender:" header; - * if this header is empty will use the original sender. * If the requested value is <CODE>SpecialAddress.NULL</CODE> will remove the "Reply-To:" header. * If the requested value is null does nothing.</P> * Is a "setX(Mail, Tx, Mail)" method. */ protected void setReplyTo(Mail newMail, MailAddress replyTo, Mail originalMail) throws MessagingException { if(replyTo != null) { - if (replyTo == SpecialAddress.SENDER) { - replyTo = getSafeApparentSender(originalMail); - - // if still null give up. - if (replyTo == null) { - return; - } - } - - // do the job InternetAddress[] iart = null; if (replyTo != SpecialAddress.NULL) { iart = new InternetAddress[1]; @@ -769,7 +766,7 @@ try { return new MailAddress(addressString); } catch(Exception e) { - log("Parse error in getReturnPath: " + addressString); + throw new MessagingException("Exception thrown in getReturnPath() parsing: " + addressString, e); } } @@ -783,13 +780,15 @@ * * @return [EMAIL PROTECTED] #getReturnPath()}, * replacing <CODE>SpecialAddress.SENDER</CODE> if applicable with the original sender, - * replacing <CODE>SpecialAddress.UNALTERED</CODE> if applicable with null, + * replacing <CODE>SpecialAddress.UNALTERED</CODE> + * and <CODE>SpecialAddress.UNALTERED</CODE> if applicable with null, * but not replacing <CODE>SpecialAddress.NULL</CODE> + * that will be handled by [EMAIL PROTECTED] #setReturnPath} */ protected MailAddress getReturnPath(Mail originalMail) throws MessagingException { MailAddress returnPath = (isStatic()) ? this.returnPath : getReturnPath(); if (returnPath != null) { - if (returnPath == SpecialAddress.UNALTERED) { + if (returnPath == SpecialAddress.UNALTERED || returnPath == SpecialAddress.RETURN_PATH) { returnPath = null; } else if (returnPath == SpecialAddress.SENDER) { @@ -844,7 +843,7 @@ try { return new MailAddress(addressString); } catch(Exception e) { - log("Parse error in getSender: " + addressString); + throw new MessagingException("Exception thrown in getSender() parsing: " + addressString, e); } } @@ -857,12 +856,13 @@ * Is a "getX(Mail)" method. * * @return [EMAIL PROTECTED] #getSender()} - * replacing <CODE>SpecialAddress.UNALTERED</CODE> if applicable with null + * replacing <CODE>SpecialAddress.UNALTERED</CODE> + * and <CODE>SpecialAddress.SENDER</CODE> if applicable with null */ protected MailAddress getSender(Mail originalMail) throws MessagingException { MailAddress sender = (isStatic()) ? this.sender : getSender(); if (sender != null) { - if (sender == SpecialAddress.UNALTERED) { + if (sender == SpecialAddress.UNALTERED || sender == SpecialAddress.SENDER) { sender = null; } } @@ -870,35 +870,14 @@ } /** - * <P>Sets the sender and the "From:" header of <I>newMail</I> to <I>sender</I>.</P> - * <P>If the requested value is <CODE>SpecialAddress.SENDER</CODE> will use the original "From:" header; - * if this header is empty will use the original "Sender:" header; - * if this header is empty will use the original sender. - * If the requested value is null does nothing.</P> + * Sets the sender and the "From:" header of <I>newMail</I> to <I>sender</I>. + * If the requested value is null does nothing. * Is a "setX(Mail, Tx, Mail)" method. */ protected void setSender(Mail newMail, MailAddress sender, Mail originalMail) throws MessagingException { if (sender != null) { - if (sender == SpecialAddress.SENDER) { - MailAddress newSender = getSafeApparentSender(originalMail); - String newFromHeader = getSafeFromHeader(originalMail); - - if (!newFromHeader.trim().equals("")) { - newMail.getMessage().setHeader(RFC2822Headers.FROM, newFromHeader); - } - - if (newSender != null) { - ((MailImpl) newMail).setSender(newSender); - } - - // The new code should be compatible with and extend the previous code: -// 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); - } + newMail.getMessage().setFrom(sender.toInternetAddress()); + ((MailImpl) newMail).setSender(sender); if (isDebug) { log("sender set to: " + sender); @@ -907,44 +886,6 @@ } /** - * <P>Gets a safe "apparent" sender using the original "From:" header if possible.</P> - * <P>Will use the original "From:" header; - * if this header is empty will use the original "Sender:" header; - * if this header is empty will use the original sender.</P> - */ - private MailAddress getSafeApparentSender(Mail originalMail) throws MessagingException { - MailAddress sender = null; - InternetAddress from = (InternetAddress) originalMail.getMessage().getFrom()[0]; - - if (from == null) { - // perhaps this is redundant, but just in case ... - from = originalMail.getSender().toInternetAddress(); - } - if (from != null) { - sender = new MailAddress(from.getAddress()); - } - - return sender; - } - - /** - * <P>Gets a safe "From:" header using the original if possible.</P> - * <P>Will use the original "From:" header; - * if this header is empty will use the original "Sender:" header; - * if this header is empty will use the original sender.</P> - */ - private String getSafeFromHeader(Mail originalMail) throws MessagingException { - MailAddress sender = getSafeApparentSender(originalMail); - String fromHeader = originalMail.getMessage().getHeader(RFC2822Headers.FROM, ","); - - if (fromHeader.trim().equals("") && sender != null) { - fromHeader = sender.toInternetAddress().toString(); - } - - return fromHeader; - } - - /** * Gets the <CODE>subject</CODE> property. * Returns a string for the new message subject. * Is a "getX()" method. @@ -980,7 +921,7 @@ */ protected String getSubjectPrefix() throws MessagingException { if(getInitParameter("prefix") == null) { - return ""; + return null; } else { return getInitParameter("prefix"); } @@ -1001,18 +942,33 @@ /** * Builds the subject of <I>newMail</I> appending the subject * of <I>originalMail</I> to <I>subjectPrefix</I>. + * Is a "setX(Mail, Tx, Mail)" method. */ protected void setSubjectPrefix(Mail newMail, String subjectPrefix, Mail originalMail) throws MessagingException { String subject = getSubject(originalMail); - if (subject == null) { - subject = originalMail.getMessage().getSubject(); - } - if (subject == null) { - subject = ""; - } - newMail.getMessage().setSubject(subjectPrefix + subject); - if (isDebug) { - log("subjectPrefix set to: " + subjectPrefix); + 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); } } @@ -1194,8 +1150,6 @@ // 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 if (getPassThrough(originalMail)) { @@ -1218,6 +1172,8 @@ setRecipients(newMail, getRecipients(originalMail), originalMail); + setTo(newMail, getTo(originalMail), originalMail); + setSubjectPrefix(newMail, getSubjectPrefix(originalMail), originalMail); if(newMail.getMessage().getHeader(RFC2822Headers.DATE) == null) { @@ -1248,9 +1204,9 @@ .append(((MailImpl) originalMail).getName()) .append(". Invalid sender domain for ") .append(newMail.getSender()) - .append(". Consider using the Redirect mailet ") + .append(". Consider using the Resend mailet ") .append("using a different sender."); - log(logBuffer.toString()); + throw new MessagingException(logBuffer.toString()); } if(!getPassThrough(originalMail)) { @@ -1330,7 +1286,7 @@ * Gets the MailAddress corresponding to the existing "Return-Path" header of * <I>mail</I>. * If empty returns <CODE>SpecialAddress.NULL</CODE>, - * if missing return <CODE>SpecialAddress.SENDER</CODE>. + * if missing return <CODE>null</CODE>. */ protected MailAddress getExistingReturnPath(Mail mail) throws MessagingException { MailAddress mailAddress = null; @@ -1467,11 +1423,25 @@ */ protected void buildAlteredMessage(Mail newMail, Mail originalMail) throws MessagingException { - MimeMessage message = originalMail.getMessage(); + 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(message); + String head = getMessageHeaders(originalMessage); boolean all = false; String messageText = getMessage(originalMail); @@ -1494,7 +1464,7 @@ case BODY: //BODY: out.println("Message:"); try { - out.println(getMessageBody(message)); + out.println(getMessageBody(originalMessage)); } catch(Exception e) { out.println("body unavailable"); } @@ -1530,7 +1500,7 @@ break; case BODY: //BODY: try { - part.setText(getMessageBody(message)); + part.setText(getMessageBody(originalMessage)); } catch(Exception e) { part.setText("body unavailable"); } @@ -1540,15 +1510,15 @@ new StringBuffer(1024) .append(head) .append("\r\nMessage:\r\n") - .append(getMessageBody(message)); + .append(getMessageBody(originalMessage)); part.setText(textBuffer.toString()); break; case MESSAGE: //MESSAGE: - part.setContent(message, "message/rfc822"); + part.setContent(originalMessage, "message/rfc822"); break; } - if ((message.getSubject() != null) && (message.getSubject().trim().length() > 0)) { - part.setFileName(message.getSubject().trim()); + if ((originalMessage.getSubject() != null) && (originalMessage.getSubject().trim().length() > 0)) { + part.setFileName(originalMessage.getSubject().trim()); } else { part.setFileName("No Subject"); } @@ -1703,6 +1673,91 @@ throw new MessagingException("Unexpected init parameters found: " + arrayToString(bad.toArray())); } + } + + /** + * 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 + */ + public static void changeSubject(MimeMessage message, String newValue) + throws MessagingException + { + 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 + } + } + } + + /** + * 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 + * @return the MIME charset name or null if no encoding applied + */ + static private String determineMailHeaderEncodingCharset(String rawText) + { + 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; } } 1.1.2.8 +8 -4 jakarta-james/src/java/org/apache/james/transport/mailets/Bounce.java Index: Bounce.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/Bounce.java,v retrieving revision 1.1.2.7 retrieving revision 1.1.2.8 diff -u -r1.1.2.7 -r1.1.2.8 --- Bounce.java 27 Jun 2003 14:34:37 -0000 1.1.2.7 +++ Bounce.java 30 Jun 2003 09:42:07 -0000 1.1.2.8 @@ -133,7 +133,7 @@ * <debug><I>true or false</I></debug> * </mailet> * </CODE></PRE> - * <P><I>notice</I>, <I>senderAddress</I> and <I>attachStackTrace</I> can be used instead of + * <P><I>notice</I>, <I>sendingAddress</I> and <I>attachStackTrace</I> can be used instead of * <I><I>message</I>, <I>sender</I> and <I>attachError</I>; such names are kept for backward compatibility.</P> * * @version CVS $Revision$ $Date$ @@ -161,6 +161,7 @@ "attachment", "message", "notice", + "sender", "sendingAddress", "prefix", "attachError", @@ -194,7 +195,7 @@ /** * @return <CODE>SpecialAddress.NULL</CODE> (the meaning of bounce) */ - protected MailAddress getReturnPath() { + protected MailAddress getReturnPath(Mail originalMail) { return SpecialAddress.NULL; } @@ -215,8 +216,11 @@ if (returnAddress == SpecialAddress.NULL) { if (isDebug) log("Processing a bounce request for a message with an empty return path. No bounce will be sent."); + if(!getPassThrough(originalMail)) { + originalMail.setState(Mail.GHOST); + } return; - } else if (returnAddress == SpecialAddress.SENDER) { + } else if (returnAddress == null) { log("WARNING: Mail to be bounced does not contain a Return-Path header."); } else { if (isDebug) 1.6.4.9 +2 -2 jakarta-james/src/java/org/apache/james/transport/mailets/Forward.java Index: Forward.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/Forward.java,v retrieving revision 1.6.4.8 retrieving revision 1.6.4.9 diff -u -r1.6.4.8 -r1.6.4.9 --- Forward.java 27 Jun 2003 14:34:37 -0000 1.6.4.8 +++ Forward.java 30 Jun 2003 09:42:07 -0000 1.6.4.9 @@ -204,7 +204,7 @@ * @return "" */ protected String getSubjectPrefix() throws MessagingException { - return ""; + return null; } /** 1.12.4.6 +1 -94 jakarta-james/src/java/org/apache/james/transport/mailets/GenericListserv.java Index: GenericListserv.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/GenericListserv.java,v retrieving revision 1.12.4.5 retrieving revision 1.12.4.6 diff -u -r1.12.4.5 -r1.12.4.6 --- GenericListserv.java 29 May 2003 20:31:17 -0000 1.12.4.5 +++ GenericListserv.java 30 Jun 2003 09:42:07 -0000 1.12.4.6 @@ -196,90 +196,6 @@ return subject.toString(); } - - /** - * 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. - * - * Under Java 1.4 it further checks if the encoding is supported under the - * current runtime environment. - * - * In some cases it returns UTF-8 as a fallback charset. This is not - * an official MIME standard yet, and most importantly not all email client - * support it, but it is likely better then the server default. - * - * Here is an example raw text: - * Subject: =?iso-8859-2?Q?leg=FAjabb_pr=F3ba_l=F5elemmel?= - * - * 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 rawText the raw (not decoded) value of the header - * @return the java charset name or null if no encoding applied - */ - static private String determineMailHeaderEncodingCharset(String rawText) - { - 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); - String javaCharset = javax.mail.internet.MimeUtility.javaCharset(mimeCharset); - - // using reflection for a JRE 1.4 function - if (charsetIsSupportedMethod == null) return javaCharset; // pre 1.4 runtime - - try { - String[] arguments = { javaCharset }; - Boolean isSupported = (Boolean)charsetIsSupportedMethod.invoke(null, arguments); - if (isSupported.booleanValue()) - return javaCharset; - else - // UTF-8 must be supported by every JRE, and it is better then server default, - // even if a few clients don't support it yet. - // I use UTF-8 instead of UTF8 because there is no java-MIME mapping, - // and official MIME code yet, so this will be directly used as a MIME - // code, and it is the quasi-standard MIME code (OE uses this). - return "UTF-8"; - } catch (java.lang.reflect.InvocationTargetException e) { - // it was thrown by Charset.isSupported, illegal charset name - return "UTF-8"; - } catch (Exception e) { - // impossible - return javaCharset; - } - } - - /** - * JRE 1.4 specific method, java.nio.charset.Charset.isSupported(String). - * This field is initialized by the static initialization block and - * is used by the determineMailHeaderEncodingCharset method. - * James doesn't require JRE 1.4 so we must use reflection. - */ - static private java.lang.reflect.Method charsetIsSupportedMethod; - - /** - * class initialization, it initializes the charsetIsSupportedMethod member - */ - static { - try { - Class charsetClass = Class.forName("java.nio.charset.Charset"); - Class[] parameterTypes = { String.class }; - charsetIsSupportedMethod = charsetClass.getMethod("isSupported", parameterTypes); - } catch (Exception e) { - charsetIsSupportedMethod = null; // pre 1.4 runtime - } - } /** * Processes the message. Assumes it is the only recipient of this forked message. @@ -334,21 +250,12 @@ .append("] "); prefix = prefixBuffer.toString(); } - String rawSubject = message.getHeader(RFC2822Headers.SUBJECT, null); - String charset = determineMailHeaderEncodingCharset(rawSubject); String subj = message.getSubject(); if (subj == null) { subj = ""; } subj = normalizeSubject(subj, prefix); - try { - message.setSubject(subj, charset); - } catch (MessagingException e) { - // known, but unsupported encoding - if (charset != null) log(charset + - " charset unsupported by the JRE, email subject may be damaged"); - message.setSubject(subj); // recover - } + AbstractRedirect.changeSubject(message, subj); } //If replies should go to this list, we need to set the header 1.9.4.10 +3 -2 jakarta-james/src/java/org/apache/james/transport/mailets/NotifyPostmaster.java Index: NotifyPostmaster.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/NotifyPostmaster.java,v retrieving revision 1.9.4.9 retrieving revision 1.9.4.10 diff -u -r1.9.4.9 -r1.9.4.10 --- NotifyPostmaster.java 27 Jun 2003 14:34:37 -0000 1.9.4.9 +++ NotifyPostmaster.java 30 Jun 2003 09:42:07 -0000 1.9.4.10 @@ -129,7 +129,7 @@ * <debug><I>true or false</I></debug> * </mailet> * </CODE></PRE> - * <P><I>notice</I>, <I>senderAddress</I> and <I>attachStackTrace</I> can be used instead of + * <P><I>notice</I>, <I>sendingAddress</I> and <I>attachStackTrace</I> can be used instead of * <I><I>message</I>, <I>sender</I> and <I>attachError</I>; such names are kept for backward compatibility.</P> * * @version CVS $Revision$ $Date$ @@ -156,6 +156,7 @@ "attachment", "message", "notice", + "sender", "sendingAddress", "prefix", "attachError", 1.10.4.11 +3 -2 jakarta-james/src/java/org/apache/james/transport/mailets/NotifySender.java Index: NotifySender.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/NotifySender.java,v retrieving revision 1.10.4.10 retrieving revision 1.10.4.11 diff -u -r1.10.4.10 -r1.10.4.11 --- NotifySender.java 27 Jun 2003 14:34:37 -0000 1.10.4.10 +++ NotifySender.java 30 Jun 2003 09:42:07 -0000 1.10.4.11 @@ -128,7 +128,7 @@ * <debug><I>true or false</I></debug> * </mailet> * </CODE></PRE> - * <P><I>notice</I>, <I>senderAddress</I> and <I>attachStackTrace</I> can be used instead of + * <P><I>notice</I>, <I>sendingAddress</I> and <I>attachStackTrace</I> can be used instead of * <I><I>message</I>, <I>sender</I> and <I>attachError</I>; such names are kept for backward compatibility.</P> * * @version CVS $Revision$ $Date$ @@ -155,6 +155,7 @@ "attachment", "message", "notice", + "sender", "sendingAddress", "prefix", "attachError", 1.18.4.14 +58 -17 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.13 retrieving revision 1.18.4.14 diff -u -r1.18.4.13 -r1.18.4.14 --- Redirect.java 27 Jun 2003 14:34:37 -0000 1.18.4.13 +++ Redirect.java 30 Jun 2003 09:42:07 -0000 1.18.4.14 @@ -90,11 +90,13 @@ * <P>A mailet providing configurable redirection services.</P> * <P>Can produce listserver, forward and notify behaviour, with the original * message intact, attached, appended or left out altogether.</P> - * <P>It is kept only for compatibility, use instead [EMAIL PROTECTED] Resend}. - * It differs from <CODE>Resend</CODE> because (i) some defaults are different, - * notably for the following parameters: <I><recipients></I>, <I><to></I> and <I><inline></I>; - * (ii) because it allows the use of the <I><static></I> parameter; - * (iii) because it lacks the <I><subject></I> parameter.</P> + * <P>It differs from [EMAIL PROTECTED] Resend} because + * (i) some defaults are different, + * notably for the following parameters: <I><recipients></I>, <I><to></I>, + * <I><returnPath></I> and <I><inline></I>; + * (ii) because it allows the use of the <I><static></I> parameter;.<BR> + * Use <CODE>Resend</CODE> if you need full control, <CODE>Redirect</CODE> if + * the more automatic behaviour of some parameters is appropriate.</P> * <P>This built in functionality is controlled by the configuration as laid out below. * In the table please note that the parameters controlling message headers * accept the <B>"unaltered"</B> value, whose meaning is to keep the associated @@ -127,10 +129,9 @@ * <TR valign=top> * <TD width="20%"><sender></TD> * <TD width="80%"> - * A single email address to appear in the From: header and become the sender.<BR> + * A single email address to appear in the From: and Return-Path: headers and become the sender.<BR> * It can include constants "sender", "postmaster" and "unaltered"; - * if "sender" is specified then it will follow a safe procedure from the - * original From: header (see [EMAIL PROTECTED] AbstractRedirect#setSender} and [EMAIL PROTECTED] AbstractRedirect#getSender(Mail)}).<BR> + * "sender" is equivalent to "unaltered".<BR> * Default: "unaltered". * </TD> * </TR> @@ -209,26 +210,34 @@ * <TD width="80%"> * A single email address to appear in the Reply-To: header.<BR> * It can include constants "sender", "postmaster" "null" and "unaltered"; - * if "sender" is specified then it will follow a safe procedure from the - * original From: header (see [EMAIL PROTECTED] AbstractRedirect#setReplyTo} and [EMAIL PROTECTED] AbstractRedirect#getReplyTo(Mail)}); * if "null" is specified it will remove this header.<BR> * Default: "unaltered". * </TD> * </TR> + * </TR> * <TR valign=top> * <TD width="20%"><returnPath></TD> * <TD width="80%"> * A single email address to appear in the Return-Path: header.<BR> - * It can include constants "sender", "postmaster" "null"and "unaltered"; + * It can include constants "sender", "postmaster" and "null"; * if "null" is specified then it will set it to <>, meaning "null return path".<BR> - * Default: "unaltered". + * Notice: the "unaltered" value is <I>not allowed</I>.<BR> + * Default: the value of the <I><sender></I> parameter, if set, otherwise remains unaltered. + * </TD> + * </TR> + * <TR valign=top> + * <TD width="20%"><subject></TD> + * <TD width="80%"> + * An optional string to use as the subject.<BR> + * Default: keep the original message subject. * </TD> * </TR> * <TR valign=top> * <TD width="20%"><prefix></TD> * <TD width="80%"> * An optional subject prefix prepended to the original message - * subject, for example: <I>[Undeliverable mail]</I>.<BR> + * subject, or to a new subject specified with the <I><subject></I> parameter.<BR> + * For example: <I>[Undeliverable mail]</I>.<BR> * Default: "". * </TD> * </TR> @@ -323,7 +332,7 @@ "replyto", "returnPath", "sender", -// "subject", + "subject", "prefix", "attachError", "isReply" @@ -432,10 +441,42 @@ } /** - * @return null + * @return the <CODE>returnPath</CODE> init parameter + * or the postmaster address + * or <CODE>SpecialAddress.SENDER</CODE> + * or <CODE>SpecialAddress.NULL</CODE> + * or <CODE>null</CODE> if missing */ - protected String getSubject() { + protected MailAddress getReturnPath() throws MessagingException { + String addressString = getInitParameter("returnPath"); + if(addressString != null) { + MailAddress specialAddress = getSpecialAddress(addressString, + new String[] {"postmaster", "sender", "null"}); + if (specialAddress != null) { + return specialAddress; + } + + try { + return new MailAddress(addressString); + } catch(Exception e) { + throw new MessagingException("Exception thrown in getReturnPath() parsing: " + addressString, e); + } + } + return null; + } + + /** + * @return [EMAIL PROTECTED] AbstractRedirect#getReturnPath()}; + * if null return [EMAIL PROTECTED] AbstractRedirect#getSender(Mail)}, + * meaning the new requested sender if any + */ + protected MailAddress getReturnPath(Mail originalMail) throws MessagingException { + MailAddress returnPath = super.getReturnPath(originalMail); + if (returnPath == null) { + returnPath = getSender(originalMail); + } + return returnPath; } /* ******************************************************************** */ 1.1.2.2 +7 -8 jakarta-james/src/java/org/apache/james/transport/mailets/Resend.java Index: Resend.java =================================================================== RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/transport/mailets/Resend.java,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- Resend.java 27 Jun 2003 14:34:38 -0000 1.1.2.1 +++ Resend.java 30 Jun 2003 09:42:07 -0000 1.1.2.2 @@ -90,8 +90,10 @@ * <P>A mailet providing configurable redirection services.</P> * <P>Can produce listserver, forward and notify behaviour, with the original * message intact, attached, appended or left out altogether. - * Should be used as a replacement to [EMAIL PROTECTED] Redirect}, as defaults are more consistent, - * and has new options available.</P> + * Can be used as a replacement to [EMAIL PROTECTED] Redirect}, having more consistent defaults, + * and new options available.<BR> + * Use <CODE>Resend</CODE> if you need full control, <CODE>Redirect</CODE> if + * the more automatic behaviour of some parameters is appropriate.</P> * <P>This built in functionality is controlled by the configuration as laid out below. * In the table please note that the parameters controlling message headers * accept the <B>"unaltered"</B> value, whose meaning is to keep the associated @@ -121,8 +123,7 @@ * <TD width="80%"> * A single email address to appear in the From: header and become the sender.<BR> * It can include constants "sender", "postmaster" and "unaltered"; - * if "sender" is specified then it will follow a safe procedure from the - * original From: header (see [EMAIL PROTECTED] AbstractRedirect#setSender} and [EMAIL PROTECTED] AbstractRedirect#getSender(Mail)}).<BR> + * "sender" is equivalent to "unaltered".<BR> * Default: "unaltered". * </TD> * </TR> @@ -201,8 +202,6 @@ * <TD width="80%"> * A single email address to appear in the Reply-To: header.<BR> * It can include constants "sender", "postmaster" "null" and "unaltered"; - * if "sender" is specified then it will follow a safe procedure from the - * original From: header (see [EMAIL PROTECTED] AbstractRedirect#setReplyTo} and [EMAIL PROTECTED] AbstractRedirect#getReplyTo(Mail)}); * if "null" is specified it will remove this header.<BR> * Default: "unaltered". * </TD> @@ -211,7 +210,7 @@ * <TD width="20%"><returnPath></TD> * <TD width="80%"> * A single email address to appear in the Return-Path: header.<BR> - * It can include constants "sender", "postmaster" "null"and "unaltered"; + * It can include constants "sender", "postmaster" "null" and "unaltered"; * if "null" is specified then it will set it to <>, meaning "null return path".<BR> * Default: "unaltered". * </TD>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]