You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by da...@apache.org on 2002/07/28 13:46:41 UTC
cvs commit: jakarta-james/src/java/org/apache/james/transport/mailets NotifyPostmaster.java Redirect.java NotifySender.java
danny 2002/07/28 04:46:41
Modified: src/java/org/apache/james/core MimeMessageWrapper.java
src/java/org/apache/james/util RFC822DateFormat.java
RFC822Date.java
src/java/org/apache/james/nntpserver NNTPHandler.java
src/java/org/apache/james/transport/mailets
NotifyPostmaster.java Redirect.java
NotifySender.java
Added: src/java/org/apache/james/util RFC2980DateFormat.java
RFC977DateFormat.java SynchronizedDateFormat.java
SimplifiedDateFormat.java
Log:
Date format synchronisation patch supplied by Peter Goldsein, cures potential problem from un-thread-safe SimpleDateFormat
Revision Changes Path
1.10 +4 -5 jakarta-james/src/java/org/apache/james/core/MimeMessageWrapper.java
Index: MimeMessageWrapper.java
===================================================================
RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/core/MimeMessageWrapper.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- MimeMessageWrapper.java 18 Apr 2002 14:49:14 -0000 1.9
+++ MimeMessageWrapper.java 28 Jul 2002 11:46:40 -0000 1.10
@@ -16,6 +16,8 @@
import java.util.Enumeration;
import java.util.Vector;
+import org.apache.james.util.RFC822DateFormat;
+
/**
* This object wraps a MimeMessage, only loading the underlying MimeMessage
* object when needed. Also tracks if changes were made to reduce
@@ -42,7 +44,7 @@
/**
* How to format a mail date
*/
- MailDateFormat mailDateFormat = new MailDateFormat();
+ RFC822DateFormat mailDateFormat = new RFC822DateFormat();
public MimeMessageWrapper(MimeMessageSource source) {
super(javax.mail.Session.getDefaultInstance(System.getProperties(), null));
@@ -346,10 +348,7 @@
String header = getHeader("Date", null);
if(header != null) {
try {
- synchronized(mailDateFormat) {
- Date date = mailDateFormat.parse(header);
- return date;
- }
+ return mailDateFormat.parse(header);
} catch(ParseException _ex) {
return null;
}
1.4 +18 -39 jakarta-james/src/java/org/apache/james/util/RFC822DateFormat.java
Index: RFC822DateFormat.java
===================================================================
RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/util/RFC822DateFormat.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- RFC822DateFormat.java 4 Oct 2001 15:17:49 -0000 1.3
+++ RFC822DateFormat.java 28 Jul 2002 11:46:40 -0000 1.4
@@ -7,60 +7,39 @@
*/
package org.apache.james.util;
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.SimpleDateFormat;
import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
+import javax.mail.internet.MailDateFormat;
/**
- * I suppose I could access some of the special messages within Sun's implementation of the JavaMail
- * API, but I've always been told not to do that. This class has one static method that takes a
- * java.util.Date object and returns a nicely formatted String version of this, formatted as per the
- * RFC822 mail date format.
+ * A thread safe wrapper for the <code>javax.mail.internet.MailDateFormat</code> class.
+ *
* @author Serge Knystautas <se...@lokitech.com>
+ * @author Peter M. Goldstein <fa...@alum.mit.edu>
*/
-public class RFC822DateFormat {
- private static DateFormat df;
- private static DecimalFormat tz;
- private static TimeZone defaultTZ;
+public class RFC822DateFormat extends SynchronizedDateFormat {
+ private static RFC822DateFormat instance;
static {
- df = new SimpleDateFormat("EE, d MMM yyyy HH:mm:ss", Locale.ENGLISH);
- tz = new DecimalFormat("00");
- defaultTZ = TimeZone.getDefault();
+ instance = new RFC822DateFormat();
}
/**
- * SimpleDateFormat will handle most of this for us, but the
- * timezone won't match, so we do that manually
+ * This static method allows us to format RFC822 dates without
+ * explicitly instantiating an RFC822DateFormat object.
*
* @return java.lang.String
* @param d Date
+ *
+ * @deprecated This method is not necessary and is preserved for API
+ * backwards compatibility. Users of this class should
+ * instantiate an instance and use it as they would any
+ * other DateFormat object.
*/
public static String toString(Date d) {
- StringBuffer sb = new StringBuffer(df.format(d));
-
- sb.append(' ');
-
- int min = TimeZone.getDefault().getRawOffset() / 1000 / 60;
-
- if (defaultTZ.useDaylightTime() && defaultTZ.inDaylightTime(d)) {
- min += 60;
- }
-
- if (min >= 0) {
- sb.append('+');
- } else {
- sb.append('-');
- }
-
- min = Math.abs(min);
-
- sb.append(tz.format(min / 60));
- sb.append(tz.format(min % 60));
+ return instance.format(d);
+ }
- return sb.toString();
+ public RFC822DateFormat() {
+ super(new MailDateFormat());
}
}
1.4 +30 -45 jakarta-james/src/java/org/apache/james/util/RFC822Date.java
Index: RFC822Date.java
===================================================================
RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/util/RFC822Date.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- RFC822Date.java 18 Jan 2002 02:48:39 -0000 1.3
+++ RFC822Date.java 28 Jul 2002 11:46:40 -0000 1.4
@@ -7,8 +7,6 @@
*/
package org.apache.james.util;
-import java.text.DateFormat;
-import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -25,22 +23,23 @@
* example - convert to timezone: String yourdate = new RFC822Date("3 Oct 2001 08:32:44 -0000", "GMT+02:00").toString()<br>
* example - convert to local timezone: String mydate = new RFC822Date("3 Oct 2001 08:32:44 -0000").toString()<br>
* @author Danny Angus (danny) <Da...@thought.co.uk><br>
+ * @author Peter M. Goldstein <fa...@alum.mit.edu><br>
+ *
+ * @deprecated Use java.util.Date in combination with org.apache.james.util.RFC822DateFormat.
*/
public class RFC822Date {
- private static DateFormat df;
+ private static SimpleDateFormat df;
private static SimpleDateFormat dx;
private static SimpleDateFormat dy;
private static SimpleDateFormat dz;
- private static DecimalFormat tz;
- private TimeZone defaultTZ;
private Date d;
+ private RFC822DateFormat rfc822Format = new RFC822DateFormat();
static {
df = new SimpleDateFormat("EE, d MMM yyyy HH:mm:ss", Locale.US);
dx = new SimpleDateFormat("EE, d MMM yyyy HH:mm:ss zzzzz", Locale.US);
dy = new SimpleDateFormat("EE d MMM yyyy HH:mm:ss zzzzz", Locale.US);
dz = new SimpleDateFormat("d MMM yyyy HH:mm:ss zzzzz", Locale.US);
- tz = new DecimalFormat("00");
}
/**
@@ -48,9 +47,8 @@
* using this machines system timezone<br>
*
*/
-public RFC822Date(){
+ public RFC822Date(){
d = new Date();
- defaultTZ = TimeZone.getDefault();
}
/**
@@ -58,9 +56,8 @@
* and this machines system timezone<br>
* @param da java.util.Date, A date object
*/
- public RFC822Date(Date da){
+ public RFC822Date(Date da) {
d = da;
- defaultTZ = TimeZone.getDefault();
}
/**
@@ -77,7 +74,6 @@
*/
public RFC822Date(Date da, String useTZ){
d = da;
- defaultTZ = TimeZone.getTimeZone(useTZ);
}
/**
@@ -89,7 +85,6 @@
*/
public RFC822Date(String rfcdate) {
setDate(rfcdate);
- defaultTZ = TimeZone.getDefault();
}
/**
* creates object from
@@ -100,7 +95,7 @@
*/
public RFC822Date(String rfcdate, String useTZ) {
setDate(rfcdate);
- defaultTZ = TimeZone.getTimeZone(useTZ);
+ setTimeZone(useTZ);
}
public void setDate(Date da){
@@ -116,17 +111,21 @@
* @param rfcdate java.lang.String - date in RFC822 format
*/
public void setDate(String rfcdate) {
- String exceptions;
- int exceptionoff;
- try{
- d= dx.parse(rfcdate);
- }catch(ParseException e){
- try{
- d= dz.parse(rfcdate);
- }catch(ParseException f){
- try{
- d= dy.parse(rfcdate);
- }catch(ParseException g){
+ try {
+ synchronized (dx) {
+ d= dx.parse(rfcdate);
+ }
+ } catch(ParseException e) {
+ try {
+ synchronized (dz) {
+ d= dz.parse(rfcdate);
+ }
+ } catch(ParseException f) {
+ try {
+ synchronized (dy) {
+ d = dy.parse(rfcdate);
+ }
+ } catch(ParseException g) {
d = new Date();
}
}
@@ -135,12 +134,12 @@
}
- public void setTimeZone(TimeZone useTZ){
- defaultTZ = useTZ;
+ public void setTimeZone(TimeZone useTZ) {
+ rfc822Format.setTimeZone(useTZ);
}
- public void setTimeZone(String useTZ){
- defaultTZ = TimeZone.getTimeZone(useTZ);
+ public void setTimeZone(String useTZ) {
+ setTimeZone(TimeZone.getTimeZone(useTZ));
}
@@ -148,7 +147,7 @@
* returns the java.util.Date object this RFC822Date represents.
* @return java.util.Date - the java.util.Date object this RFC822Date represents.
*/
- public Date getDate(){
+ public Date getDate() {
return d;
}
@@ -158,21 +157,7 @@
* @return java.lang.String - date as a string formated for RFC822 compliance
*
*/
- public String toString() {
- StringBuffer sb = new StringBuffer(df.format(d));
- sb.append(' ');
- int min = defaultTZ.getRawOffset() / 1000 / 60;
- if (defaultTZ.useDaylightTime() && defaultTZ.inDaylightTime(d)) {
- min += 60;
- }
- if (min >= 0) {
- sb.append('+');
- } else {
- sb.append('-');
- }
- min = Math.abs(min);
- sb.append(tz.format(min / 60));
- sb.append(tz.format(min % 60));
- return sb.toString();
+ public String toString() {
+ return rfc822Format.format(d);
}
}
1.1 jakarta-james/src/java/org/apache/james/util/RFC2980DateFormat.java
Index: RFC2980DateFormat.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.util;
import java.util.Locale;
/**
* A thread-safe date formatting class to produce dates formatted in accord with the
* specifications of section 3.2 of RFC 2980.
*
* @author Peter M. Goldstein <fa...@alum.mit.edu>
*/
public class RFC2980DateFormat extends SynchronizedDateFormat {
public RFC2980DateFormat() {
super("yyyyMMddHHmmss", Locale.ENGLISH);
}
}
1.1 jakarta-james/src/java/org/apache/james/util/RFC977DateFormat.java
Index: RFC977DateFormat.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* A thread-safe date formatting class to produce dates formatted in accord with the
* specifications of RFC 977.
*
* @author Peter M. Goldstein <fa...@alum.mit.edu>
*/
public class RFC977DateFormat implements SimplifiedDateFormat {
private final SynchronizedDateFormat internalLongDateFormat;
private final SynchronizedDateFormat internalShortDateFormat;
public RFC977DateFormat() {
internalLongDateFormat = new SynchronizedDateFormat("yyyyMMdd HHmmss", Locale.ENGLISH);
internalShortDateFormat = new SynchronizedDateFormat("yyMMdd HHmmss", Locale.ENGLISH);
}
/**
* This method returns the long form of the RFC977 Date
*
* @return java.lang.String
* @param d Date
*/
public String format(Date d) {
return internalLongDateFormat.format(d);
}
/**
* Parses text from the beginning of the given string to produce a date.
* The method may not use the entire text of the given string.
* <p>
* This method is designed to be thread safe, so we wrap our delegated
* parse method in an appropriate synchronized block.
*
* @param source A <code>String</code> whose beginning should be parsed.
* @return A <code>Date</code> parsed from the string.
* @exception ParseException if the beginning of the specified string
* cannot be parsed.
*/
public Date parse(String source) throws ParseException {
source = source.trim();
if (source.indexOf(' ') == 6) {
return internalShortDateFormat.parse(source);
} else {
return internalLongDateFormat.parse(source);
}
}
/**
* Sets the time zone of this SynchronizedDateFormat object.
* @param zone the given new time zone.
*/
public void setTimeZone(TimeZone zone) {
synchronized(this) {
internalShortDateFormat.setTimeZone(zone);
internalLongDateFormat.setTimeZone(zone);
}
}
/**
* Gets the time zone.
* @return the time zone associated with this SynchronizedDateFormat.
*/
public TimeZone getTimeZone() {
synchronized(this) {
return internalShortDateFormat.getTimeZone();
}
}
/**
* Specify whether or not date/time parsing is to be lenient. With
* lenient parsing, the parser may use heuristics to interpret inputs that
* do not precisely match this object's format. With strict parsing,
* inputs must match this object's format.
* @param lenient when true, parsing is lenient
* @see java.util.Calendar#setLenient
*/
public void setLenient(boolean lenient)
{
synchronized(this) {
internalShortDateFormat.setLenient(lenient);
internalLongDateFormat.setLenient(lenient);
}
}
/**
* Tell whether date/time parsing is to be lenient.
* @return whether this SynchronizedDateFormat is lenient.
*/
public boolean isLenient()
{
synchronized(this) {
return internalShortDateFormat.isLenient();
}
}
/**
* Overrides equals
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof RFC977DateFormat)) {
return false;
}
RFC977DateFormat theOtherRFC977DateFormat = (RFC977DateFormat)obj;
synchronized (this) {
return ((internalShortDateFormat.equals(theOtherRFC977DateFormat.internalShortDateFormat)) &&
(internalLongDateFormat.equals(theOtherRFC977DateFormat.internalLongDateFormat)));
}
}
/**
* Overrides hashCode
*/
public int hashCode() {
return (int)(internalLongDateFormat.hashCode() & internalShortDateFormat.hashCode());
}
}
1.1 jakarta-james/src/java/org/apache/james/util/SynchronizedDateFormat.java
Index: SynchronizedDateFormat.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.util;
import java.text.ParseException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* This class is designed to be a synchronized wrapper for a
* <code>java.text.DateFormat</code> subclass. In general,
* these subclasses (most notably the <code>java.text.SimpleDateFormat</code>
* classes are not thread safe, so we need to synchronize on the
* internal DateFormat for all delegated calls.
*
* @author Peter M. Goldstein <fa...@alum.mit.edu>
*/
public class SynchronizedDateFormat implements SimplifiedDateFormat {
private final DateFormat internalDateFormat;
public SynchronizedDateFormat(String pattern, Locale locale) {
internalDateFormat = new SimpleDateFormat(pattern, locale);
}
protected SynchronizedDateFormat(DateFormat theDateFormat) {
internalDateFormat = theDateFormat;
}
/**
* SimpleDateFormat will handle most of this for us, but we
* want to ensure thread safety, so we wrap the call in a
* synchronized block.
*
* @return java.lang.String
* @param d Date
*/
public String format(Date d) {
synchronized (internalDateFormat) {
return internalDateFormat.format(d);
}
}
/**
* Parses text from the beginning of the given string to produce a date.
* The method may not use the entire text of the given string.
* <p>
* This method is designed to be thread safe, so we wrap our delegated
* parse method in an appropriate synchronized block.
*
* @param source A <code>String</code> whose beginning should be parsed.
* @return A <code>Date</code> parsed from the string.
* @exception ParseException if the beginning of the specified string
* cannot be parsed.
*/
public Date parse(String source) throws ParseException {
synchronized (internalDateFormat) {
return internalDateFormat.parse(source);
}
}
/**
* Sets the time zone of this SynchronizedDateFormat object.
* @param zone the given new time zone.
*/
public void setTimeZone(TimeZone zone) {
synchronized(internalDateFormat) {
internalDateFormat.setTimeZone(zone);
}
}
/**
* Gets the time zone.
* @return the time zone associated with this SynchronizedDateFormat.
*/
public TimeZone getTimeZone() {
synchronized(internalDateFormat) {
return internalDateFormat.getTimeZone();
}
}
/**
* Specify whether or not date/time parsing is to be lenient. With
* lenient parsing, the parser may use heuristics to interpret inputs that
* do not precisely match this object's format. With strict parsing,
* inputs must match this object's format.
* @param lenient when true, parsing is lenient
* @see java.util.Calendar#setLenient
*/
public void setLenient(boolean lenient)
{
synchronized(internalDateFormat) {
internalDateFormat.setLenient(lenient);
}
}
/**
* Tell whether date/time parsing is to be lenient.
* @return whether this SynchronizedDateFormat is lenient.
*/
public boolean isLenient()
{
synchronized(internalDateFormat) {
return internalDateFormat.isLenient();
}
}
/**
* Overrides hashCode
*/
public int hashCode() {
synchronized(internalDateFormat) {
return internalDateFormat.hashCode();
}
}
/**
* Overrides equals
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
synchronized(internalDateFormat) {
return internalDateFormat.equals(obj);
}
}
}
1.1 jakarta-james/src/java/org/apache/james/util/SimplifiedDateFormat.java
Index: SimplifiedDateFormat.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.james.util;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* This interface is designed to provide a simplified subset of the
* methods provided by the <code>java.text.DateFormat</code> class.
*
* This interface is necessary because of the difficulty in writing
* thread safe classes that inherit from <code>java.text.DateFormat</code>.
* This difficulty leads us to approach the problem using composition
* rather than inheritance. In general classes that implement this
* interface will delegate these calls to an internal DateFormat object.
*
* @author Peter M. Goldstein <fa...@alum.mit.edu>
*/
public interface SimplifiedDateFormat {
/**
* Formats a Date into a date/time string.
* @param date the time value to be formatted into a time string.
* @return the formatted time string.
*/
public String format(Date d);
/**
* Parses text from the beginning of the given string to produce a date.
* The method may not use the entire text of the given string.
*
* @param source A <code>String</code> whose beginning should be parsed.
* @return A <code>Date</code> parsed from the string.
* @exception ParseException if the beginning of the specified string
* cannot be parsed.
*/
public Date parse(String source) throws ParseException;
/**
* Sets the time zone of this SimplifiedDateFormat object.
* @param zone the given new time zone.
*/
public void setTimeZone(TimeZone zone);
/**
* Gets the time zone.
* @return the time zone associated with this SimplifiedDateFormat.
*/
public TimeZone getTimeZone();
/**
* Specify whether or not date/time parsing is to be lenient. With
* lenient parsing, the parser may use heuristics to interpret inputs that
* do not precisely match this object's format. With strict parsing,
* inputs must match this object's format.
* @param lenient when true, parsing is lenient
* @see java.util.Calendar#setLenient
*/
public void setLenient(boolean lenient);
/**
* Tell whether date/time parsing is to be lenient.
* @return whether this SimplifiedDateFormat is lenient.
*/
public boolean isLenient();
}
1.13 +14 -11 jakarta-james/src/java/org/apache/james/nntpserver/NNTPHandler.java
Index: NNTPHandler.java
===================================================================
RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/nntpserver/NNTPHandler.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- NNTPHandler.java 27 Jul 2002 08:16:25 -0000 1.12
+++ NNTPHandler.java 28 Jul 2002 11:46:41 -0000 1.13
@@ -21,6 +21,9 @@
import org.apache.james.nntpserver.repository.NNTPGroup;
import org.apache.james.nntpserver.repository.NNTPLineReaderImpl;
import org.apache.james.nntpserver.repository.NNTPRepository;
+import org.apache.james.util.RFC977DateFormat;
+import org.apache.james.util.RFC2980DateFormat;
+import org.apache.james.util.SimplifiedDateFormat;
import java.io.BufferedReader;
import java.io.IOException;
@@ -29,13 +32,12 @@
import java.net.Socket;
import java.text.DateFormat;
import java.text.ParseException;
-import java.text.SimpleDateFormat;
import java.util.*;
/**
* The NNTP protocol is defined by RFC 977.
- * This implementation is based on IETF draft 13, posted on 2nd April '2001.
- * URL: http://www.ietf.org/internet-drafts/draft-ietf-nntpext-base-13.txt
+ * This implementation is based on IETF draft 15, posted on 15th July '2002
+ * URL: http://www.ietf.org/internet-drafts/draft-ietf-nntpext-base-15.txt
*
* Common NNTP extensions are in RFC 2980.
*
@@ -239,9 +241,9 @@
private void doNEWGROUPS(StringTokenizer tok) {
// see section 11.3
// there seeem to be few differences.
- // draft-ietf-nntpext-base-13.txt mentions 231 in section 11.3.1,
+ // draft-ietf-nntpext-base-15.txt mentions 231 in section 11.3.1,
// but examples have response code 230. rfc977 has 231 response code.
- // both draft-ietf-nntpext-base-13.txt and rfc977 have only group names
+ // both draft-ietf-nntpext-base-15.txt and rfc977 have only group names
// in response lines, but INN sends
// '<group name> <last article> <first article> <posting allowed>'
// NOTE: following INN over either document.
@@ -265,9 +267,11 @@
String time = tok.nextToken();
boolean utc = ( tok.hasMoreTokens() );
Date d = new Date();
- DateFormat df = ( date.length() == 8 ) ? DF_DATEFROM_LONG : DF_DATEFROM_SHORT;
try {
- Date dt = df.parse(date+" "+time);
+ StringBuffer dateStringBuffer = new StringBuffer(date);
+ dateStringBuffer.append(" ");
+ dateStringBuffer.append(time);
+ Date dt = DF_RFC977.parse(dateStringBuffer.toString());
if ( utc )
dt = new Date(dt.getTime()+UTC_OFFSET);
return dt;
@@ -282,17 +286,16 @@
}
// used to calculate DATE from - see 11.3
- public static final DateFormat DF_DATEFROM_LONG = new SimpleDateFormat("yyyyMMdd HHmmss");
- public static final DateFormat DF_DATEFROM_SHORT = new SimpleDateFormat("yyMMdd HHmmss");
+ public static final SimplifiedDateFormat DF_RFC977 = new RFC977DateFormat();
// Date format for the DATE keyword - see 11.1.1
- public static final DateFormat DF_DATE = new SimpleDateFormat("yyyyMMddHHmmss");
+ public static final SimplifiedDateFormat DF_RFC2980 = new RFC2980DateFormat();
public static final long UTC_OFFSET = Calendar.getInstance().get(Calendar.ZONE_OFFSET);
private void doDATE() {
//Calendar c = Calendar.getInstance();
//long UTC_OFFSET = c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET);
Date dt = new Date(System.currentTimeMillis()-UTC_OFFSET);
- String dtStr = DF_DATE.format(new Date(dt.getTime() - UTC_OFFSET));
+ String dtStr = DF_RFC2980.format(new Date(dt.getTime() - UTC_OFFSET));
writer.println("111 "+dtStr);
}
private void doQUIT() {
1.5 +5 -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.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- NotifyPostmaster.java 18 Jan 2002 02:48:38 -0000 1.4
+++ NotifyPostmaster.java 28 Jul 2002 11:46:41 -0000 1.5
@@ -7,7 +7,7 @@
*/
package org.apache.james.transport.mailets;
-import org.apache.james.util.RFC822Date;
+import org.apache.james.util.RFC822DateFormat;
import org.apache.mailet.GenericMailet;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -49,6 +50,8 @@
boolean attachStackTrace = false;
String noticeText = null;
+ private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
+
public void init() throws MessagingException {
if (getInitParameter("sendingAddress") == null) {
notifier = getMailetContext().getPostmaster();
@@ -175,7 +178,7 @@
//Set additional headers
if (reply.getHeader("Date")==null){
- reply.setHeader("Date",new RFC822Date().toString());
+ reply.setHeader("Date", rfc822DateFormat.format(new Date()));
}
String subject = message.getSubject();
if (subject == null) {
1.5 +567 -551 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.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Redirect.java 18 Jun 2002 21:49:53 -0000 1.4
+++ Redirect.java 28 Jul 2002 11:46:41 -0000 1.5
@@ -1,551 +1,567 @@
-/*
- * Copyright (C) The Apache Software Foundation. All rights reserved.
- *
- * This software is published under the terms of the Apache Software License
- * version 1.1, a copy of which has been included with this distribution in
- * the LICENSE file.
- */
-package org.apache.james.transport.mailets;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.StringTokenizer;
-
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Session;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-
-import org.apache.james.util.RFC822Date;
-
-import org.apache.mailet.GenericMailet;
-import org.apache.mailet.Mail;
-import org.apache.mailet.MailAddress;
-
-
-/**
-*<P>A mailet providing configurable redirection services<BR>
-*This mailet can produce listserver, forward and notify behaviour, with the original
-*message intact, attached, appended or left out altogether.<BR>
-*This built in functionality is controlled by the configuration as laid out below.</P>
-*<P>However it is also designed to be easily subclassed to make authoring redirection
-*mailets simple. <BR>
-*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:</P>
-*<UL>
-*<LI>attachError() , should error messages be appended to the message</LI>
-*<LI>getAttachementType(), what should be attached to the message</LI>
-*<LI>getInLineType(), what should be included in the message</LI>
-*<LI>getMessage(), The text of the message itself</LI>
-*<LI>getRecipients(), the recipients the mail is sent to</LI>
-*<LI>getReplyTo(), where replys to this message will be sent</LI>
-*<LI>getSender(), who the mail is from</LI>
-*<LI>getSubjectPrefix(), a prefix to be added to the message subject</LI>
-*<LI>getTo(), a list of people to whom the mail is *apparently* sent</LI>
-*<LI>getPassThrough(), should this mailet GHOST the original message.</LI>
-*<LI>isStatic(), should this mailet run the get methods for every mail, or just
-*once. </LI>
-*</UL>
-*<P>The configuration parameters are:</P>
-*<TABLE width="75%" border="0" cellspacing="2" cellpadding="2">
-*<TR>
-*<TD width="20%"><recipients></TD>
-*<TD width="80%">A comma delimited list of email addresses for recipients of
-*this message, it will use the "to" list if not specified. These
-*addresses will only appear in the To: header if no "to" list is
-*supplied.</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><to></TD>
-*<TD width="80%">A comma delimited list of addresses to appear in the To: header,
-*the email will only be delivered to these addresses if they are in the recipients
-*list.<BR>
-*The recipients list will be used if this is not supplied</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><sender></TD>
-*<TD width="80%">A single email address to appear in the From: header <BR>
-*It can include constants "sender" and "postmaster"</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><message></TD>
-*<TD width="80%">A text message to be the body of the email. Can be omitted.</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><inline></TD>
-*<TD width="80%">
-*<P>One of the following items:</P>
-*<UL>
-*<LI>unaltered The original message is the new
-* message, for forwarding/aliasing</LI>
-*<LI>heads The
-* headers of the original message are appended to the message</LI>
-*<LI>body The
-* body of the original is appended to the new message</LI>
-*<LI>all Both
-* headers and body are appended</LI>
-*<LI>none Neither
-* body nor headers are appended</LI>
-*</UL>
-*</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><attachment></TD>
-*<TD width="80%">
-*<P>One of the following items:</P>
-*<UL>
-*<LI>heads The headers of the original
-* are attached as text</LI>
-*<LI>body The body of the original
-* is attached as text</LI>
-*<LI>all Both
-* headers and body are attached as a single text file</LI>
-*<LI>none Nothing is attached</LI>
-*<LI>message The original message is attached as type message/rfc822,
-* this means that it can, in many cases, be opened, resent, fw'd, replied
-* to etc by email client software.</LI>
-*</UL>
-*</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><passThrough></TD>
-*<TD width="80%">TRUE or FALSE, if true the original message continues in the
-*mailet processor after this mailet is finished. False causes the original
-*to be stopped.</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><attachError></TD>
-*<TD width="80%">TRUE or FALSE, if true any error message available to the
-*mailet is appended to the message body (except in the case of inline ==
-*unaltered)</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><replyto></TD>
-*<TD width="80%">A single email address to appear in the Rely-To: header, can
-*also be "sender" or "postmaster", this header is not
-*set if this is omited.</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><prefix></TD>
-*<TD width="80%">An optional subject prefix prepended to the original message
-*subject, for example..<BR>
-*Undeliverable mail:</TD>
-*</TR>
-*<TR>
-*<TD width="20%"><static></TD>
-*<TD width="80%">
-*<P>TRUE or FALSE, if this is true it hints to the mailet that none of the
-*parameters are set dynamically, and therefore they can be set once in
-*the init method.<BR>
-*False tells the mailet to call all the "getters" for every mail
-*processed.</P>
-*<P>This defaults to false.<BR>
-*It should be TRUE in all cases, except where one of the getter methods
-*has been overriden to provide dynamic values, such as a listserve which
-*might override getRecipients() to get a list from a users repository.</P>
-*</TD>
-*</TR>
-*</TABLE>
-*
-*<P>Example:</P>
-*<P> <mailet match="RecipientIs=test@localhost" class="Redirect"><BR>
-*<recipients>x@localhost, y@localhost, z@localhost</recipients><BR>
-*<to>list@localhost</to><BR>
-*<sender>owner@localhost</sender><BR>
-*<message>sent on from James</message><BR>
-*<inline>unaltered</inline><BR>
-*<passThrough>FALSE</passThrough><BR>
-*<replyto>postmaster</replyto><BR>
-*<prefix>[test mailing]</prefix><BR>
-*<static>TRUE</static><BR>
-*<passThrough>FALSE</passThrough><BR>
-*</mailet><BR>
-*</P>
-*<P>and:</P>
-*<P> <mailet match="All" class="Redirect"><BR>
-*<recipients>x@localhost</recipients><BR>
-*<sender>postmaster</sender><BR>
-*<message>Message marked as spam:<BR>
-*</message><BR>
-*<inline>heads</inline><BR>
-*<attachment>message</attachment><BR>
-*<passThrough>FALSE</passThrough><BR>
-*<attachError>TRUE</attachError><BR>
-*<replyto>postmaster</replyto><BR>
-*<prefix>[spam notification]</prefix><BR>
-*<static>TRUE</static><BR>
-*<passThrough>FALSE</passThrough><BR>
-*</mailet></P>
- *
- * @author Danny Angus <da...@thought.co.uk>
- *
- */
-public class Redirect extends GenericMailet {
- private static int ALL = 3;
- private static int BODY = 2;
- private static int HEADS = 1;
- private static int MESSAGE = 5;
- private static int NONE = 4;
- private static int UNALTERED = 0;
- private InternetAddress[] apparentlyTo;
- private String messageText;
- private Collection recipients;
- private MailAddress replyTo;
- private MailAddress sender;
-
- /**
-* returns one of these values to indicate how to attach the original message
-*<ul>
-* <li>BODY : original message body is attached as plain text to the new message</li>
-* <li>HEADS : original message headers are attached as plain text to the new message</li>
-* <li>ALL : original is attached as plain text with all headers</li>
-* <li>MESSAGE : original message is attached as type message/rfc822, a complete mail message.</li>
-* <li>NONE : original is not attached</li>
-*</ul>
-*
-*/
- public int getAttachmentType() {
- if(getInitParameter("attachment") == null) {
- return NONE;
- } else {
- return getTypeCode(getInitParameter("attachment"));
- }
- }
-
- /**
-* returns one of these values to indicate how to append the original message
-*<ul>
-* <li>UNALTERED : original message is the new message body</li>
-* <li>BODY : original message body is appended to the new message</li>
-* <li>HEADS : original message headers are appended to the new message</li>
-* <li>ALL : original is appended with all headers</li>
-* <li>NONE : original is not appended</li>
-*</ul>
-*/
- public int getInLineType() {
- if(getInitParameter("inline") == null) {
- return BODY;
- } else {
- return getTypeCode(getInitParameter("inline"));
- }
- }
-
- /**
- * Add Description
- *
- * @return Document return!
- */
- public String getMailetInfo() {
- return "Resend Mailet";
- }
-
- /**
-* must return either an empty string, or a message to which the redirect can be attached/appended
-*/
- public String getMessage() {
- if(getInitParameter("message") == null) {
- return "";
- } else {
- return getInitParameter("message");
- }
- }
-
- /**
-* return true to allow thie original message to continue through the processor, false to GHOST it
-*/
- public boolean getPassThrough() {
- if(getInitParameter("passThrough") == null) {
- return false;
- } else {
- return new Boolean(getInitParameter("passThrough")).booleanValue();
- }
- }
-
- /**
-* must return a Collection of recipient MailAddress'es
-*/
- public Collection getRecipients() {
- Collection newRecipients = new HashSet();
- String addressList = (getInitParameter("recipients") == null)
- ? getInitParameter("to")
- : getInitParameter("recipients");
- StringTokenizer st = new StringTokenizer(addressList, ",", false);
- while(st.hasMoreTokens()) {
- try {
- newRecipients.add(new MailAddress(st.nextToken()));
- } catch(Exception e) {
- log("add recipient failed in getRecipients");
- }
- }
- return newRecipients;
- }
-
- /**
-* return the reply to address as a string
-*/
- public MailAddress getReplyTo() {
- String sr = getInitParameter("replyto");
- if(sr != null) {
- MailAddress rv;
- if(sr.compareTo("postmaster") == 0) {
- rv = getMailetContext().getPostmaster();
- return rv;
- }
- if(sr.compareTo("sender") == 0) {
- return null;
- }
- try {
- rv = new MailAddress(sr);
- return rv;
- } catch(Exception e) {
- log("Parse error in getReplyTo " + sr);
- }
- }
- return null;
- }
-
- /**
-* returns the senders address, as a MailAddress
-*/
- public MailAddress getSender() {
- String sr = getInitParameter("sender");
- if(sr != null) {
- MailAddress rv;
- if(sr.compareTo("postmaster") == 0) {
- rv = getMailetContext().getPostmaster();
- return rv;
- }
- if(sr.compareTo("sender") == 0) {
- return null;
- }
- try {
- rv = new MailAddress(sr);
- return rv;
- } catch(Exception e) {
- log("Parse error in getSender " + sr);
- }
- }
- return null;
- }
-
- /**
-* return true to reduce calls to getTo, getSender, getRecipients, getReplyTo amd getMessage
-* where these values don't change (eg hard coded, or got at startup from the mailet config)<br>
-* return false where any of these methods generate their results dynamically eg in response to the message being processed,
-* or by refrence to a repository of users
-*/
- public boolean isStatic() {
- if(getInitParameter("static") == null) {
- return false;
- }
- return new Boolean(getInitParameter("static")).booleanValue();
- }
-
- /**
-* return a prefix for the message subject
-*/
- public String getSubjectPrefix() {
- if(getInitParameter("prefix") == null) {
- return "";
- } else {
- return getInitParameter("prefix");
- }
- }
-
- /**
-* returns an array of InternetAddress 'es for the To: header
-*/
- public InternetAddress[] getTo() {
- String addressList = (getInitParameter("to") == null)
- ? getInitParameter("recipients") : getInitParameter("to");
- StringTokenizer rec = new StringTokenizer(addressList, ",");
- int tokensn = rec.countTokens();
- InternetAddress[] iaarray = new InternetAddress[tokensn];
- String tokenx = "";
- for(int i = 0; i < tokensn; ++i) {
- try {
- tokenx = rec.nextToken();
- iaarray[i] = new InternetAddress(tokenx);
- } catch(Exception e) {
- log("Internet address exception in getTo()");
- }
- }
- return iaarray;
- }
-
- /**
-* return true to append a description of any error to the main body part
-* if getInlineType does not return "UNALTERED"
-*/
- public boolean attachError() {
- if(getInitParameter("attachError") == null) {
- return false;
- } else {
- return new Boolean(getInitParameter("attachError")).booleanValue();
- }
- }
-
- /**
-* init will setup static values for sender, recipients, message text, and reply to
-* <br> if isStatic() returns true
-* it calls getSender(), getReplyTo(), getMessage(), and getRecipients() and getTo()
-*
-*/
- public void init() throws MessagingException {
- log("redirect init");
- if(isStatic()) {
- sender = (getSender() == null) ? getMailetContext().getPostmaster() : getSender();
- replyTo = (getReplyTo() == null) ? getMailetContext().getPostmaster() : getReplyTo();
- messageText = getMessage();
- recipients = getRecipients();
- apparentlyTo = getTo();
- log("static, sender=" + sender + ", replyTo=" + replyTo + ", message=" + messageText +
- " ");
- }
- }
-
- /**
-*
-* Service does the hard work,and redirects the mail in the form specified
-*
-*
-*/
- public void service(Mail mail) throws MessagingException {
- if(!isStatic()) {
- sender = getSender();
- replyTo = getReplyTo();
- messageText = getMessage();
- recipients = getRecipients();
- apparentlyTo = getTo();
- }
- MimeMessage message = mail.getMessage();
- MimeMessage reply = new MimeMessage(Session.getDefaultInstance(System.getProperties(),
- null));
- //Create the message
- if(getInLineType() != UNALTERED) {
- log("alter message inline=:" + getInLineType());
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- Enumeration heads = message.getAllHeaderLines();
- String head = "";
- while(heads.hasMoreElements()) {
- head += (heads.nextElement().toString() + "\n");
- }
- boolean all = false;
- if(messageText != null) {
- out.println(messageText);
- }
- switch(getInLineType()) {
- case 3: //ALL:
- all = true;
- case 1: //HEADS:
- out.println("Message Headers:");
- out.println(head);
- if(!all) {
- break;
- }
- case 2: //BODY:
- out.println("Message:");
- try {
- out.println(message.getContent().toString());
- } catch(Exception e) {
- out.println("body unavailable");
- }
- break;
- default:
- case 4: //NONE:
- break;
- }
- MimeMultipart multipart = new MimeMultipart();
- //Add message as the first mime body part
- MimeBodyPart part = new MimeBodyPart();
- part.setText(sout.toString());
- part.setDisposition("inline");
- multipart.addBodyPart(part);
- if(getAttachmentType() != NONE) {
- part = new MimeBodyPart();
- switch(getAttachmentType()) {
- case 1: //HEADS:
- part.setText(head);
- break;
- case 2: //BODY:
- try {
- part.setText(message.getContent().toString());
- } catch(Exception e) {
- part.setText("body unavailable");
- }
- break;
- case 3: //ALL:
- part.setText(head + "\n\n" + message.toString());
- break;
- case 5: //MESSAGE:
- part.setContent(message, "message/rfc822");
- break;
- }
- part.setDisposition("Attachment");
- multipart.addBodyPart(part);
- }
- reply.setContent(multipart);
- reply.setHeader("Content-Type", multipart.getContentType());
- } else {
- log("message resent unaltered:");
- reply = message;
- }
- //Set additional headers
- reply.setSubject(getSubjectPrefix() + message.getSubject());
- if(reply.getHeader("Date") == null) {
- reply.setHeader("Date", new RFC822Date().toString());
- }
- reply.setRecipients(Message.RecipientType.TO, apparentlyTo);
- if(replyTo != null) {
- InternetAddress[] iart = new InternetAddress[1];
- iart[0] = replyTo.toInternetAddress();
- reply.setReplyTo(iart);
- }
- if(sender == null) {
- reply.setHeader("From", message.getHeader("From", ","));
- } else {
- reply.setFrom(sender.toInternetAddress());
- }
- //Send it off...
- getMailetContext().sendMail(sender, recipients, reply);
- if(!getPassThrough()) {
- mail.setState(Mail.GHOST);
- }
- }
-
- /**
-* A private method to convert types from string to int.
-*/
- private int getTypeCode(String param) {
- int code;
- param = param.toLowerCase();
- if(param.compareTo("unaltered") == 0) {
- return 0;
- }
- if(param.compareTo("heads") == 0) {
- return 1;
- }
- if(param.compareTo("body") == 0) {
- return 2;
- }
- if(param.compareTo("all") == 0) {
- return 3;
- }
- if(param.compareTo("none") == 0) {
- return 4;
- }
- if(param.compareTo("message") == 0) {
- return 5;
- }
- return 4;
- }
-}
\ No newline at end of file
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE file.
+ */
+package org.apache.james.transport.mailets;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.apache.james.util.RFC822DateFormat;
+
+import org.apache.mailet.GenericMailet;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+
+/**
+*<P>A mailet providing configurable redirection services<BR>
+*This mailet can produce listserver, forward and notify behaviour, with the original
+*message intact, attached, appended or left out altogether.<BR>
+*This built in functionality is controlled by the configuration as laid out below.</P>
+*<P>However it is also designed to be easily subclassed to make authoring redirection
+*mailets simple. <BR>
+*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:</P>
+*<UL>
+*<LI>attachError() , should error messages be appended to the message</LI>
+*<LI>getAttachementType(), what should be attached to the message</LI>
+*<LI>getInLineType(), what should be included in the message</LI>
+*<LI>getMessage(), The text of the message itself</LI>
+*<LI>getRecipients(), the recipients the mail is sent to</LI>
+*<LI>getReplyTo(), where replys to this message will be sent</LI>
+*<LI>getSender(), who the mail is from</LI>
+*<LI>getSubjectPrefix(), a prefix to be added to the message subject</LI>
+*<LI>getTo(), a list of people to whom the mail is *apparently* sent</LI>
+*<LI>getPassThrough(), should this mailet GHOST the original message.</LI>
+*<LI>isStatic(), should this mailet run the get methods for every mail, or just
+*once. </LI>
+*</UL>
+*<P>The configuration parameters are:</P>
+*<TABLE width="75%" border="0" cellspacing="2" cellpadding="2">
+*<TR>
+*<TD width="20%"><recipients></TD>
+*<TD width="80%">A comma delimited list of email addresses for recipients of
+*this message, it will use the "to" list if not specified. These
+*addresses will only appear in the To: header if no "to" list is
+*supplied.</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><to></TD>
+*<TD width="80%">A comma delimited list of addresses to appear in the To: header,
+*the email will only be delivered to these addresses if they are in the recipients
+*list.<BR>
+*The recipients list will be used if this is not supplied</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><sender></TD>
+*<TD width="80%">A single email address to appear in the From: header <BR>
+*It can include constants "sender" and "postmaster"</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><message></TD>
+*<TD width="80%">A text message to be the body of the email. Can be omitted.</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><inline></TD>
+*<TD width="80%">
+*<P>One of the following items:</P>
+*<UL>
+*<LI>unaltered The original message is the new
+* message, for forwarding/aliasing</LI>
+*<LI>heads The
+* headers of the original message are appended to the message</LI>
+*<LI>body The
+* body of the original is appended to the new message</LI>
+*<LI>all Both
+* headers and body are appended</LI>
+*<LI>none Neither
+* body nor headers are appended</LI>
+*</UL>
+*</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><attachment></TD>
+*<TD width="80%">
+*<P>One of the following items:</P>
+*<UL>
+*<LI>heads The headers of the original
+* are attached as text</LI>
+*<LI>body The body of the original
+* is attached as text</LI>
+*<LI>all Both
+* headers and body are attached as a single text file</LI>
+*<LI>none Nothing is attached</LI>
+*<LI>message The original message is attached as type message/rfc822,
+* this means that it can, in many cases, be opened, resent, fw'd, replied
+* to etc by email client software.</LI>
+*</UL>
+*</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><passThrough></TD>
+*<TD width="80%">TRUE or FALSE, if true the original message continues in the
+*mailet processor after this mailet is finished. False causes the original
+*to be stopped.</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><attachError></TD>
+*<TD width="80%">TRUE or FALSE, if true any error message available to the
+*mailet is appended to the message body (except in the case of inline ==
+*unaltered)</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><replyto></TD>
+*<TD width="80%">A single email address to appear in the Rely-To: header, can
+*also be "sender" or "postmaster", this header is not
+*set if this is omited.</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><prefix></TD>
+*<TD width="80%">An optional subject prefix prepended to the original message
+*subject, for example..<BR>
+*Undeliverable mail:</TD>
+*</TR>
+*<TR>
+*<TD width="20%"><static></TD>
+*<TD width="80%">
+*<P>TRUE or FALSE, if this is true it hints to the mailet that none of the
+*parameters are set dynamically, and therefore they can be set once in
+*the init method.<BR>
+*False tells the mailet to call all the "getters" for every mail
+*processed.</P>
+*<P>This defaults to false.<BR>
+*It should be TRUE in all cases, except where one of the getter methods
+*has been overriden to provide dynamic values, such as a listserve which
+*might override getRecipients() to get a list from a users repository.</P>
+*</TD>
+*</TR>
+*</TABLE>
+*
+*<P>Example:</P>
+*<P> <mailet match="RecipientIs=test@localhost" class="Redirect"><BR>
+*<recipients>x@localhost, y@localhost, z@localhost</recipients><BR>
+*<to>list@localhost</to><BR>
+*<sender>owner@localhost</sender><BR>
+*<message>sent on from James</message><BR>
+*<inline>unaltered</inline><BR>
+*<passThrough>FALSE</passThrough><BR>
+*<replyto>postmaster</replyto><BR>
+*<prefix>[test mailing]</prefix><BR>
+*<static>TRUE</static><BR>
+*<passThrough>FALSE</passThrough><BR>
+*</mailet><BR>
+*</P>
+*<P>and:</P>
+*<P> <mailet match="All" class="Redirect"><BR>
+*<recipients>x@localhost</recipients><BR>
+*<sender>postmaster</sender><BR>
+*<message>Message marked as spam:<BR>
+*</message><BR>
+*<inline>heads</inline><BR>
+*<attachment>message</attachment><BR>
+*<passThrough>FALSE</passThrough><BR>
+*<attachError>TRUE</attachError><BR>
+*<replyto>postmaster</replyto><BR>
+*<prefix>[spam notification]</prefix><BR>
+*<static>TRUE</static><BR>
+*<passThrough>FALSE</passThrough><BR>
+*</mailet></P>
+ *
+ * @author Danny Angus <da...@thought.co.uk>
+ *
+ */
+public class Redirect extends GenericMailet {
+ private static final int UNALTERED = 0;
+ private static final int HEADS = 1;
+ private static final int BODY = 2;
+ private static final int ALL = 3;
+ private static final int NONE = 4;
+ private static final int MESSAGE = 5;
+ private InternetAddress[] apparentlyTo;
+ private String messageText;
+ private Collection recipients;
+ private MailAddress replyTo;
+ private MailAddress sender;
+
+ private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
+
+ /**
+ * returns one of these values to indicate how to attach the original message
+ *<ul>
+ * <li>BODY : original message body is attached as plain text to the new message</li>
+ * <li>HEADS : original message headers are attached as plain text to the new message</li>
+ * <li>ALL : original is attached as plain text with all headers</li>
+ * <li>MESSAGE : original message is attached as type message/rfc822, a complete mail message.</li>
+ * <li>NONE : original is not attached</li>
+ *</ul>
+ *
+ */
+ public int getAttachmentType() {
+ if(getInitParameter("attachment") == null) {
+ return NONE;
+ } else {
+ return getTypeCode(getInitParameter("attachment"));
+ }
+ }
+
+ /**
+* returns one of these values to indicate how to append the original message
+*<ul>
+* <li>UNALTERED : original message is the new message body</li>
+* <li>BODY : original message body is appended to the new message</li>
+* <li>HEADS : original message headers are appended to the new message</li>
+* <li>ALL : original is appended with all headers</li>
+* <li>NONE : original is not appended</li>
+*</ul>
+*/
+ public int getInLineType() {
+ if(getInitParameter("inline") == null) {
+ return BODY;
+ } else {
+ return getTypeCode(getInitParameter("inline"));
+ }
+ }
+
+ /**
+ * Add Description
+ *
+ * @return Document return!
+ */
+ public String getMailetInfo() {
+ return "Resend Mailet";
+ }
+
+ /**
+* must return either an empty string, or a message to which the redirect can be attached/appended
+*/
+ public String getMessage() {
+ if(getInitParameter("message") == null) {
+ return "";
+ } else {
+ return getInitParameter("message");
+ }
+ }
+
+ /**
+* return true to allow thie original message to continue through the processor, false to GHOST it
+*/
+ public boolean getPassThrough() {
+ if(getInitParameter("passThrough") == null) {
+ return false;
+ } else {
+ return new Boolean(getInitParameter("passThrough")).booleanValue();
+ }
+ }
+
+ /**
+* must return a Collection of recipient MailAddress'es
+*/
+ public Collection getRecipients() {
+ Collection newRecipients = new HashSet();
+ String addressList = (getInitParameter("recipients") == null)
+ ? getInitParameter("to")
+ : getInitParameter("recipients");
+ StringTokenizer st = new StringTokenizer(addressList, ",", false);
+ while(st.hasMoreTokens()) {
+ try {
+ newRecipients.add(new MailAddress(st.nextToken()));
+ } catch(Exception e) {
+ log("add recipient failed in getRecipients");
+ }
+ }
+ return newRecipients;
+ }
+
+ /**
+* return the reply to address as a string
+*/
+ public MailAddress getReplyTo() {
+ String sr = getInitParameter("replyto");
+ if(sr != null) {
+ MailAddress rv;
+ if(sr.compareTo("postmaster") == 0) {
+ rv = getMailetContext().getPostmaster();
+ return rv;
+ }
+ if(sr.compareTo("sender") == 0) {
+ return null;
+ }
+ try {
+ rv = new MailAddress(sr);
+ return rv;
+ } catch(Exception e) {
+ log("Parse error in getReplyTo " + sr);
+ }
+ }
+ return null;
+ }
+
+ /**
+* returns the senders address, as a MailAddress
+*/
+ public MailAddress getSender() {
+ String sr = getInitParameter("sender");
+ if(sr != null) {
+ MailAddress rv;
+ if(sr.compareTo("postmaster") == 0) {
+ rv = getMailetContext().getPostmaster();
+ return rv;
+ }
+ if(sr.compareTo("sender") == 0) {
+ return null;
+ }
+ try {
+ rv = new MailAddress(sr);
+ return rv;
+ } catch(Exception e) {
+ log("Parse error in getSender " + sr);
+ }
+ }
+ return null;
+ }
+
+ /**
+* return true to reduce calls to getTo, getSender, getRecipients, getReplyTo amd getMessage
+* where these values don't change (eg hard coded, or got at startup from the mailet config)<br>
+* return false where any of these methods generate their results dynamically eg in response to the message being processed,
+* or by refrence to a repository of users
+*/
+ public boolean isStatic() {
+ if(getInitParameter("static") == null) {
+ return false;
+ }
+ return new Boolean(getInitParameter("static")).booleanValue();
+ }
+
+ /**
+* return a prefix for the message subject
+*/
+ public String getSubjectPrefix() {
+ if(getInitParameter("prefix") == null) {
+ return "";
+ } else {
+ return getInitParameter("prefix") + " ";
+ }
+ }
+
+ /**
+* returns an array of InternetAddress 'es for the To: header
+*/
+ public InternetAddress[] getTo() {
+ String addressList = (getInitParameter("to") == null)
+ ? getInitParameter("recipients") : getInitParameter("to");
+ StringTokenizer rec = new StringTokenizer(addressList, ",");
+ int tokensn = rec.countTokens();
+ InternetAddress[] iaarray = new InternetAddress[tokensn];
+ String tokenx = "";
+ for(int i = 0; i < tokensn; ++i) {
+ try {
+ tokenx = rec.nextToken();
+ iaarray[i] = new InternetAddress(tokenx);
+ } catch(Exception e) {
+ log("Internet address exception in getTo()");
+ }
+ }
+ return iaarray;
+ }
+
+ /**
+* return true to append a description of any error to the main body part
+* if getInlineType does not return "UNALTERED"
+*/
+ public boolean attachError() {
+ if(getInitParameter("attachError") == null) {
+ return false;
+ } else {
+ return new Boolean(getInitParameter("attachError")).booleanValue();
+ }
+ }
+
+ /**
+* init will setup static values for sender, recipients, message text, and reply to
+* <br> if isStatic() returns true
+* it calls getSender(), getReplyTo(), getMessage(), and getRecipients() and getTo()
+*
+*/
+ public void init() throws MessagingException {
+ log("redirect init");
+ if(isStatic()) {
+ sender = (getSender() == null) ? getMailetContext().getPostmaster() : getSender();
+ replyTo = (getReplyTo() == null) ? getMailetContext().getPostmaster() : getReplyTo();
+ messageText = getMessage();
+ recipients = getRecipients();
+ apparentlyTo = getTo();
+ StringBuffer logBuffer = new StringBuffer("static, sender=");
+ logBuffer.append(sender);
+ logBuffer.append(", replyTo=");
+ logBuffer.append(replyTo);
+ logBuffer.append(", message=");
+ logBuffer.append(messageText);
+ logBuffer.append(" ");
+ log(logBuffer.toString());
+ }
+ }
+
+ /**
+*
+* Service does the hard work,and redirects the mail in the form specified
+*
+*
+*/
+ public void service(Mail mail) throws MessagingException {
+ if(!isStatic()) {
+ sender = getSender();
+ replyTo = getReplyTo();
+ messageText = getMessage();
+ recipients = getRecipients();
+ apparentlyTo = getTo();
+ }
+ MimeMessage message = mail.getMessage();
+ MimeMessage reply = new MimeMessage(Session.getDefaultInstance(System.getProperties(),
+ null));
+ //Create the message
+ if(getInLineType() != UNALTERED) {
+ log("alter message inline=:" + getInLineType());
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ Enumeration heads = message.getAllHeaderLines();
+ String head = "";
+ StringBuffer headBuffer = new StringBuffer();
+ while(heads.hasMoreElements()) {
+ headBuffer.append(heads.nextElement().toString());
+ headBuffer.append("\n");
+ }
+ head = headBuffer.toString();
+ boolean all = false;
+ if(messageText != null) {
+ out.println(messageText);
+ }
+ switch(getInLineType()) {
+ case ALL: //ALL:
+ all = true;
+ case HEADS: //HEADS:
+ out.println("Message Headers:");
+ out.println(head);
+ if(!all) {
+ break;
+ }
+ case BODY: //BODY:
+ out.println("Message:");
+ try {
+ out.println(message.getContent().toString());
+ } catch(Exception e) {
+ out.println("body unavailable");
+ }
+ break;
+ default:
+ case NONE: //NONE:
+ break;
+ }
+ MimeMultipart multipart = new MimeMultipart();
+ //Add message as the first mime body part
+ MimeBodyPart part = new MimeBodyPart();
+ part.setText(sout.toString());
+ part.setDisposition("inline");
+ multipart.addBodyPart(part);
+ if(getAttachmentType() != NONE) {
+ part = new MimeBodyPart();
+ switch(getAttachmentType()) {
+ case HEADS: //HEADS:
+ part.setText(head);
+ break;
+ case BODY: //BODY:
+ try {
+ part.setText(message.getContent().toString());
+ } catch(Exception e) {
+ part.setText("body unavailable");
+ }
+ break;
+ case ALL: //ALL:
+ StringBuffer textBuffer = new StringBuffer(head);
+ textBuffer.append("\n\n");
+ textBuffer.append(message.toString());
+ part.setText(textBuffer.toString());
+ break;
+ case MESSAGE: //MESSAGE:
+ part.setContent(message, "message/rfc822");
+ break;
+ }
+ part.setDisposition("Attachment");
+ multipart.addBodyPart(part);
+ }
+ reply.setContent(multipart);
+ reply.setHeader("Content-Type", multipart.getContentType());
+ } else {
+ log("message resent unaltered:");
+ reply = message;
+ }
+ //Set additional headers
+ reply.setSubject(getSubjectPrefix() + message.getSubject());
+ if(reply.getHeader("Date") == null) {
+ reply.setHeader("Date", rfc822DateFormat.format(new Date()));
+ }
+ reply.setRecipients(Message.RecipientType.TO, apparentlyTo);
+ if(replyTo != null) {
+ InternetAddress[] iart = new InternetAddress[1];
+ iart[0] = replyTo.toInternetAddress();
+ reply.setReplyTo(iart);
+ }
+ if(sender == null) {
+ reply.setHeader("From", message.getHeader("From", ","));
+ sender = new MailAddress(((InternetAddress)message.getFrom()[0]).getAddress());
+ } else {
+ reply.setFrom(sender.toInternetAddress());
+ }
+ //Send it off...
+ getMailetContext().sendMail(sender, recipients, reply);
+ if(!getPassThrough()) {
+ mail.setState(Mail.GHOST);
+ }
+ }
+
+ /**
+* A private method to convert types from string to int.
+*/
+ private int getTypeCode(String param) {
+ int code;
+ param = param.toLowerCase();
+ 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;
+ }
+}
1.5 +5 -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.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- NotifySender.java 18 Jan 2002 02:48:38 -0000 1.4
+++ NotifySender.java 28 Jul 2002 11:46:41 -0000 1.5
@@ -7,7 +7,7 @@
*/
package org.apache.james.transport.mailets;
-import org.apache.james.util.RFC822Date;
+import org.apache.james.util.RFC822DateFormat;
import org.apache.mailet.GenericMailet;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@@ -48,6 +49,8 @@
boolean attachStackTrace = false;
String noticeText = null;
+ private RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
+
public void init() throws MessagingException {
if (getInitParameter("sendingAddress") == null) {
notifier = getMailetContext().getPostmaster();
@@ -160,7 +163,7 @@
//Set additional headers
if (reply.getHeader("Date")==null){
- reply.setHeader("Date",new RFC822Date().toString());
+ reply.setHeader("Date", rfc822DateFormat.format(new Date()));
}
String subject = message.getSubject();
if (subject == null) {
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>