git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271203 13f79535-47bb-0310-9956-ffa450edef68master
@@ -1,409 +0,0 @@ | |||||
/* | |||||
* 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.txt file. | |||||
*/ | |||||
package org.apache.tools.ant.taskdefs; | |||||
import java.io.BufferedInputStream; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.PrintStream; | |||||
import java.util.ArrayList; | |||||
import java.util.Iterator; | |||||
import java.util.StringTokenizer; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.tools.ant.Task; | |||||
import org.apache.tools.mail.MailMessage; | |||||
/** | |||||
* A task to send SMTP email. <p> | |||||
* | |||||
* | |||||
* <tableborder="1" cellpadding="3" cellspacing="0"> | |||||
* | |||||
* <trbgcolor="#CCCCFF"> | |||||
* | |||||
* <th> | |||||
* Attribute | |||||
* </th> | |||||
* | |||||
* <th> | |||||
* Description | |||||
* </th> | |||||
* | |||||
* <th> | |||||
* Required | |||||
* </th> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* from | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Email address of sender. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Yes | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* mailhost | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Host name of the mail server. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* No, default to "localhost" | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* toList | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Comma-separated list of recipients. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Yes | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* subject | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Email subject line. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* No | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* files | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Filename(s) of text to send in the body of the email. Multiple files | |||||
* are comma-separated. | |||||
* </td> | |||||
* | |||||
* <tdrowspan="2"> | |||||
* One of these two attributes | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* message | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Message to send inthe body of the email. | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* </table> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* includefilenames | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Includes filenames before file contents when set to true. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* No, default is <I>false</I> | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* <p> | |||||
* | |||||
* | |||||
* | |||||
* @author glenn_twiggs@bmc.com | |||||
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||||
*/ | |||||
public class SendEmail extends Task | |||||
{ | |||||
private String mailhost = "localhost"; | |||||
private int mailport = MailMessage.DEFAULT_PORT; | |||||
private ArrayList files = new ArrayList(); | |||||
/** | |||||
* failure flag | |||||
*/ | |||||
private boolean failOnError = true; | |||||
private String from; | |||||
private boolean includefilenames; | |||||
private String message; | |||||
private String subject; | |||||
private String toList; | |||||
/** | |||||
* Creates new SendEmail | |||||
*/ | |||||
public SendEmail() | |||||
{ | |||||
} | |||||
/** | |||||
* Sets the FailOnError attribute of the MimeMail object | |||||
* | |||||
* @param failOnError The new FailOnError value | |||||
* @since 1.5 | |||||
*/ | |||||
public void setFailOnError( boolean failOnError ) | |||||
{ | |||||
this.failOnError = failOnError; | |||||
} | |||||
/** | |||||
* Sets the file parameter of this build task. | |||||
* | |||||
* @param filenames Filenames to include as the message body of this email. | |||||
*/ | |||||
public void setFiles( String filenames ) | |||||
throws TaskException | |||||
{ | |||||
StringTokenizer t = new StringTokenizer( filenames, ", " ); | |||||
while( t.hasMoreTokens() ) | |||||
{ | |||||
files.add( resolveFile( t.nextToken() ) ); | |||||
} | |||||
} | |||||
/** | |||||
* Sets the from parameter of this build task. | |||||
* | |||||
* @param from Email address of sender. | |||||
*/ | |||||
public void setFrom( String from ) | |||||
{ | |||||
this.from = from; | |||||
} | |||||
/** | |||||
* Sets Includefilenames attribute | |||||
* | |||||
* @param includefilenames Set to true if file names are to be included. | |||||
* @since 1.5 | |||||
*/ | |||||
public void setIncludefilenames( boolean includefilenames ) | |||||
{ | |||||
this.includefilenames = includefilenames; | |||||
} | |||||
/** | |||||
* Sets the mailhost parameter of this build task. | |||||
* | |||||
* @param mailhost Mail host name. | |||||
*/ | |||||
public void setMailhost( String mailhost ) | |||||
{ | |||||
this.mailhost = mailhost; | |||||
} | |||||
/** | |||||
* Sets the mailport parameter of this build task. | |||||
* | |||||
* @param value mail port name. | |||||
*/ | |||||
public void setMailport( Integer value ) | |||||
{ | |||||
this.mailport = value.intValue(); | |||||
} | |||||
/** | |||||
* Sets the message parameter of this build task. | |||||
* | |||||
* @param message Message body of this email. | |||||
*/ | |||||
public void setMessage( String message ) | |||||
{ | |||||
this.message = message; | |||||
} | |||||
/** | |||||
* Sets the subject parameter of this build task. | |||||
* | |||||
* @param subject Subject of this email. | |||||
*/ | |||||
public void setSubject( String subject ) | |||||
{ | |||||
this.subject = subject; | |||||
} | |||||
/** | |||||
* Sets the toList parameter of this build task. | |||||
* | |||||
* @param toList Comma-separated list of email recipient addreses. | |||||
*/ | |||||
public void setToList( String toList ) | |||||
{ | |||||
this.toList = toList; | |||||
} | |||||
/** | |||||
* Executes this build task. | |||||
* | |||||
* @throws TaskException if there is an error during task execution. | |||||
*/ | |||||
public void execute() | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
MailMessage mailMessage = new MailMessage( mailhost ); | |||||
mailMessage.setPort( mailport ); | |||||
if( from != null ) | |||||
{ | |||||
mailMessage.from( from ); | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "Attribute \"from\" is required." ); | |||||
} | |||||
if( toList != null ) | |||||
{ | |||||
StringTokenizer t = new StringTokenizer( toList, ", ", false ); | |||||
while( t.hasMoreTokens() ) | |||||
{ | |||||
mailMessage.to( t.nextToken() ); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "Attribute \"toList\" is required." ); | |||||
} | |||||
if( subject != null ) | |||||
{ | |||||
mailMessage.setSubject( subject ); | |||||
} | |||||
if( !files.isEmpty() ) | |||||
{ | |||||
PrintStream out = mailMessage.getPrintStream(); | |||||
for( Iterator e = files.iterator(); e.hasNext(); ) | |||||
{ | |||||
File file = (File)e.next(); | |||||
if( file.exists() && file.canRead() ) | |||||
{ | |||||
int bufsize = 1024; | |||||
int length; | |||||
byte[] buf = new byte[ bufsize ]; | |||||
if( includefilenames ) | |||||
{ | |||||
String filename = file.getName(); | |||||
int filenamelength = filename.length(); | |||||
out.println( filename ); | |||||
for( int star = 0; star < filenamelength; star++ ) | |||||
{ | |||||
out.print( '=' ); | |||||
} | |||||
out.println(); | |||||
} | |||||
BufferedInputStream in = null; | |||||
try | |||||
{ | |||||
in = new BufferedInputStream( | |||||
new FileInputStream( file ), bufsize ); | |||||
while( ( length = in.read( buf, 0, bufsize ) ) != -1 ) | |||||
{ | |||||
out.write( buf, 0, length ); | |||||
} | |||||
if( includefilenames ) | |||||
{ | |||||
out.println(); | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
if( in != null ) | |||||
{ | |||||
try | |||||
{ | |||||
in.close(); | |||||
} | |||||
catch( IOException ioe ) | |||||
{ | |||||
} | |||||
} | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "File \"" + file.getName() | |||||
+ "\" does not exist or is not readable." ); | |||||
} | |||||
} | |||||
} | |||||
else if( message != null ) | |||||
{ | |||||
PrintStream out = mailMessage.getPrintStream(); | |||||
out.print( message ); | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "Attribute \"file\" or \"message\" is required." ); | |||||
} | |||||
getLogger().info( "Sending email" ); | |||||
mailMessage.sendAndClose(); | |||||
} | |||||
catch( IOException ioe ) | |||||
{ | |||||
String err = "IO error sending mail " + ioe.toString(); | |||||
if( failOnError ) | |||||
{ | |||||
throw new TaskException( err, ioe ); | |||||
} | |||||
else | |||||
{ | |||||
getLogger().error( err ); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,535 +0,0 @@ | |||||
/* | |||||
* 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.txt file. | |||||
*/ | |||||
package org.apache.tools.mail; | |||||
import java.io.BufferedOutputStream; | |||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
import java.io.PrintStream; | |||||
import java.net.InetAddress; | |||||
import java.net.Socket; | |||||
import java.util.ArrayList; | |||||
import java.util.Enumeration; | |||||
import java.util.Hashtable; | |||||
import java.util.Iterator; | |||||
/** | |||||
* A class to help send SMTP email. This class is an improvement on the | |||||
* sun.net.smtp.SmtpClient class found in the JDK. This version has extra | |||||
* functionality, and can be used with JVMs that did not extend from the JDK. | |||||
* It's not as robust as the JavaMail Standard Extension classes, but it's | |||||
* easier to use and easier to install, and has an Open Source license. <p> | |||||
* | |||||
* It can be used like this: <blockquote><pre> | |||||
* String mailhost = "localhost"; // or another mail host | |||||
* String from = "Mail Message Servlet <MailMessage@server.com>"; | |||||
* String to = "to@you.com"; | |||||
* String cc1 = "cc1@you.com"; | |||||
* String cc2 = "cc2@you.com"; | |||||
* String bcc = "bcc@you.com"; | |||||
* | |||||
* MailMessage msg = new MailMessage(mailhost); | |||||
* msg.setPort(25); | |||||
* msg.from(from); | |||||
* msg.to(to); | |||||
* msg.cc(cc1); | |||||
* msg.cc(cc2); | |||||
* msg.bcc(bcc); | |||||
* msg.setSubject("Test subject"); | |||||
* PrintStream out = msg.getPrintStream(); | |||||
* | |||||
* Iterator enum = req.getParameterNames(); | |||||
* while (enum.hasNext()) { | |||||
* String name = (String)enum.next(); | |||||
* String value = req.getParameter(name); | |||||
* out.println(name + " = " + value); | |||||
* } | |||||
* | |||||
* msg.sendAndClose(); | |||||
* </pre></blockquote> <p> | |||||
* | |||||
* Be sure to set the from address, then set the recepient addresses, then set | |||||
* the subject and other headers, then get the PrintStream, then write the | |||||
* message, and finally send and close. The class does minimal error checking | |||||
* internally; it counts on the mail host to complain if there's any | |||||
* malformatted input or out of order execution. <p> | |||||
* | |||||
* An attachment mechanism based on RFC 1521 could be implemented on top of this | |||||
* class. In the meanwhile, JavaMail is the best solution for sending email with | |||||
* attachments. <p> | |||||
* | |||||
* Still to do: | |||||
* <ul> | |||||
* <li> Figure out how to close the connection in case of error | |||||
* </ul> | |||||
* | |||||
* | |||||
* @author Jason Hunter | |||||
* @version 1.1, 2000/03/19, added angle brackets to address, helps some servers | |||||
* version 1.0, 1999/12/29 | |||||
*/ | |||||
public class MailMessage | |||||
{ | |||||
/** | |||||
* default port for SMTP: 25 | |||||
*/ | |||||
public final static int DEFAULT_PORT = 25; | |||||
/** | |||||
* host port for the mail server | |||||
*/ | |||||
private int port = DEFAULT_PORT; | |||||
/** | |||||
* list of email addresses to cc to | |||||
*/ | |||||
private ArrayList cc; | |||||
/** | |||||
* sender email address | |||||
*/ | |||||
private String from; | |||||
/** | |||||
* headers to send in the mail | |||||
*/ | |||||
private Hashtable headers; | |||||
/** | |||||
* host name for the mail server | |||||
*/ | |||||
private String host; | |||||
private SmtpResponseReader in; | |||||
private MailPrintStream out; | |||||
private Socket socket; | |||||
/** | |||||
* list of email addresses to send to | |||||
*/ | |||||
private ArrayList to; | |||||
/** | |||||
* Constructs a new MailMessage to send an email. Use localhost as the mail | |||||
* server. | |||||
* | |||||
* @exception IOException if there's any problem contacting the mail server | |||||
*/ | |||||
public MailMessage() | |||||
throws IOException | |||||
{ | |||||
this( "localhost" ); | |||||
} | |||||
/** | |||||
* Constructs a new MailMessage to send an email. Use the given host as the | |||||
* mail server. | |||||
* | |||||
* @param host the mail server to use | |||||
* @exception IOException if there's any problem contacting the mail server | |||||
*/ | |||||
public MailMessage( String host ) | |||||
throws IOException | |||||
{ | |||||
this.host = host; | |||||
to = new ArrayList(); | |||||
cc = new ArrayList(); | |||||
headers = new Hashtable(); | |||||
setHeader( "X-Mailer", "org.apache.tools.mail.MailMessage (jakarta.apache.org)" ); | |||||
connect(); | |||||
sendHelo(); | |||||
} | |||||
// Make a limited attempt to extract a sanitized email address | |||||
// Prefer text in <brackets>, ignore anything in (parentheses) | |||||
static String sanitizeAddress( String s ) | |||||
{ | |||||
int paramDepth = 0; | |||||
int start = 0; | |||||
int end = 0; | |||||
int len = s.length(); | |||||
for( int i = 0; i < len; i++ ) | |||||
{ | |||||
char c = s.charAt( i ); | |||||
if( c == '(' ) | |||||
{ | |||||
paramDepth++; | |||||
if( start == 0 ) | |||||
{ | |||||
end = i;// support "address (name)" | |||||
} | |||||
} | |||||
else if( c == ')' ) | |||||
{ | |||||
paramDepth--; | |||||
if( end == 0 ) | |||||
{ | |||||
start = i + 1;// support "(name) address" | |||||
} | |||||
} | |||||
else if( paramDepth == 0 && c == '<' ) | |||||
{ | |||||
start = i + 1; | |||||
} | |||||
else if( paramDepth == 0 && c == '>' ) | |||||
{ | |||||
end = i; | |||||
} | |||||
} | |||||
if( end == 0 ) | |||||
{ | |||||
end = len; | |||||
} | |||||
return s.substring( start, end ); | |||||
} | |||||
/** | |||||
* Sets the named header to the given value. RFC 822 provides the rules for | |||||
* what text may constitute a header name and value. | |||||
* | |||||
* @param name The new Header value | |||||
* @param value The new Header value | |||||
*/ | |||||
public void setHeader( String name, String value ) | |||||
{ | |||||
// Blindly trust the user doesn't set any invalid headers | |||||
headers.put( name, value ); | |||||
} | |||||
/** | |||||
* Set the port to connect to the SMTP host. | |||||
* | |||||
* @param port the port to use for connection. | |||||
* @see #DEFAULT_PORT | |||||
*/ | |||||
public void setPort( int port ) | |||||
{ | |||||
this.port = port; | |||||
} | |||||
/** | |||||
* Sets the subject of the mail message. Actually sets the "Subject" header. | |||||
* | |||||
* @param subj The new Subject value | |||||
*/ | |||||
public void setSubject( String subj ) | |||||
{ | |||||
headers.put( "Subject", subj ); | |||||
} | |||||
/** | |||||
* Returns a PrintStream that can be used to write the body of the message. | |||||
* A stream is used since email bodies are byte-oriented. A writer could be | |||||
* wrapped on top if necessary for internationalization. | |||||
* | |||||
* @return The PrintStream value | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public PrintStream getPrintStream() | |||||
throws IOException | |||||
{ | |||||
setFromHeader(); | |||||
setToHeader(); | |||||
setCcHeader(); | |||||
sendData(); | |||||
flushHeaders(); | |||||
return out; | |||||
} | |||||
/** | |||||
* Sets the bcc address. Does NOT set any header since it's a *blind* copy. | |||||
* This method may be called multiple times. | |||||
* | |||||
* @param bcc Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void bcc( String bcc ) | |||||
throws IOException | |||||
{ | |||||
sendRcpt( bcc ); | |||||
// No need to keep track of Bcc'd addresses | |||||
} | |||||
/** | |||||
* Sets the cc address. Also sets the "Cc" header. This method may be called | |||||
* multiple times. | |||||
* | |||||
* @param cc Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void cc( String cc ) | |||||
throws IOException | |||||
{ | |||||
sendRcpt( cc ); | |||||
this.cc.add( cc ); | |||||
} | |||||
/** | |||||
* Sets the from address. Also sets the "From" header. This method should be | |||||
* called only once. | |||||
* | |||||
* @param from Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void from( String from ) | |||||
throws IOException | |||||
{ | |||||
sendFrom( from ); | |||||
this.from = from; | |||||
} | |||||
/** | |||||
* Sends the message and closes the connection to the server. The | |||||
* MailMessage object cannot be reused. | |||||
* | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void sendAndClose() | |||||
throws IOException | |||||
{ | |||||
sendDot(); | |||||
sendQuit(); | |||||
disconnect(); | |||||
} | |||||
/** | |||||
* Sets the to address. Also sets the "To" header. This method may be called | |||||
* multiple times. | |||||
* | |||||
* @param to Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void to( String to ) | |||||
throws IOException | |||||
{ | |||||
sendRcpt( to ); | |||||
this.to.add( to ); | |||||
} | |||||
void setCcHeader() | |||||
{ | |||||
setHeader( "Cc", vectorToList( cc ) ); | |||||
} | |||||
void setFromHeader() | |||||
{ | |||||
setHeader( "From", from ); | |||||
} | |||||
void setToHeader() | |||||
{ | |||||
setHeader( "To", vectorToList( to ) ); | |||||
} | |||||
void getReady() | |||||
throws IOException | |||||
{ | |||||
String response = in.getResponse(); | |||||
int[] ok = {220}; | |||||
if( !isResponseOK( response, ok ) ) | |||||
{ | |||||
throw new IOException( | |||||
"Didn't get introduction from server: " + response ); | |||||
} | |||||
} | |||||
boolean isResponseOK( String response, int[] ok ) | |||||
{ | |||||
// Check that the response is one of the valid codes | |||||
for( int i = 0; i < ok.length; i++ ) | |||||
{ | |||||
if( response.startsWith( "" + ok[ i ] ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
// * * * * * Raw protocol methods below here * * * * * | |||||
void connect() | |||||
throws IOException | |||||
{ | |||||
socket = new Socket( host, port ); | |||||
out = new MailPrintStream( | |||||
new BufferedOutputStream( | |||||
socket.getOutputStream() ) ); | |||||
in = new SmtpResponseReader( socket.getInputStream() ); | |||||
getReady(); | |||||
} | |||||
void disconnect() | |||||
throws IOException | |||||
{ | |||||
if( out != null ) | |||||
{ | |||||
out.close(); | |||||
} | |||||
if( in != null ) | |||||
{ | |||||
in.close(); | |||||
} | |||||
if( socket != null ) | |||||
{ | |||||
socket.close(); | |||||
} | |||||
} | |||||
void flushHeaders() | |||||
throws IOException | |||||
{ | |||||
// XXX Should I care about order here? | |||||
Enumeration e = headers.keys(); | |||||
while( e.hasMoreElements() ) | |||||
{ | |||||
String name = (String)e.nextElement(); | |||||
String value = (String)headers.get( name ); | |||||
out.println( name + ": " + value ); | |||||
} | |||||
out.println(); | |||||
out.flush(); | |||||
} | |||||
void send( String msg, int[] ok ) | |||||
throws IOException | |||||
{ | |||||
out.rawPrint( msg + "\r\n" );// raw supports <CRLF>.<CRLF> | |||||
//System.out.println("S: " + msg); | |||||
String response = in.getResponse(); | |||||
//System.out.println("R: " + response); | |||||
if( !isResponseOK( response, ok ) ) | |||||
{ | |||||
throw new IOException( | |||||
"Unexpected reply to command: " + msg + ": " + response ); | |||||
} | |||||
} | |||||
void sendData() | |||||
throws IOException | |||||
{ | |||||
int[] ok = {354}; | |||||
send( "DATA", ok ); | |||||
} | |||||
void sendDot() | |||||
throws IOException | |||||
{ | |||||
int[] ok = {250}; | |||||
send( "\r\n.", ok );// make sure dot is on new line | |||||
} | |||||
void sendFrom( String from ) | |||||
throws IOException | |||||
{ | |||||
int[] ok = {250}; | |||||
send( "MAIL FROM: " + "<" + sanitizeAddress( from ) + ">", ok ); | |||||
} | |||||
void sendHelo() | |||||
throws IOException | |||||
{ | |||||
String local = InetAddress.getLocalHost().getHostName(); | |||||
int[] ok = {250}; | |||||
send( "HELO " + local, ok ); | |||||
} | |||||
void sendQuit() | |||||
throws IOException | |||||
{ | |||||
int[] ok = {221}; | |||||
send( "QUIT", ok ); | |||||
} | |||||
void sendRcpt( String rcpt ) | |||||
throws IOException | |||||
{ | |||||
int[] ok = {250, 251}; | |||||
send( "RCPT TO: " + "<" + sanitizeAddress( rcpt ) + ">", ok ); | |||||
} | |||||
String vectorToList( ArrayList v ) | |||||
{ | |||||
StringBuffer buf = new StringBuffer(); | |||||
Iterator e = v.iterator(); | |||||
while( e.hasNext() ) | |||||
{ | |||||
buf.append( e.next() ); | |||||
if( e.hasNext() ) | |||||
{ | |||||
buf.append( ", " ); | |||||
} | |||||
} | |||||
return buf.toString(); | |||||
} | |||||
} | |||||
// This PrintStream subclass makes sure that <CRLF>. becomes <CRLF>.. | |||||
// per RFC 821. It also ensures that new lines are always \r\n. | |||||
// | |||||
class MailPrintStream extends PrintStream | |||||
{ | |||||
int lastChar; | |||||
public MailPrintStream( OutputStream out ) | |||||
{ | |||||
super( out, true );// deprecated, but email is byte-oriented | |||||
} | |||||
// Mac does \n\r, but that's tough to distinguish from Windows \r\n\r\n. | |||||
// Don't tackle that problem right now. | |||||
public void write( int b ) | |||||
{ | |||||
if( b == '\n' && lastChar != '\r' ) | |||||
{ | |||||
rawWrite( '\r' );// ensure always \r\n | |||||
rawWrite( b ); | |||||
} | |||||
else if( b == '.' && lastChar == '\n' ) | |||||
{ | |||||
rawWrite( '.' );// add extra dot | |||||
rawWrite( b ); | |||||
} | |||||
else | |||||
{ | |||||
rawWrite( b ); | |||||
} | |||||
lastChar = b; | |||||
} | |||||
public void write( byte buf[], int off, int len ) | |||||
{ | |||||
for( int i = 0; i < len; i++ ) | |||||
{ | |||||
write( buf[ off + i ] ); | |||||
} | |||||
} | |||||
void rawPrint( String s ) | |||||
{ | |||||
int len = s.length(); | |||||
for( int i = 0; i < len; i++ ) | |||||
{ | |||||
rawWrite( s.charAt( i ) ); | |||||
} | |||||
} | |||||
void rawWrite( int b ) | |||||
{ | |||||
super.write( b ); | |||||
} | |||||
} | |||||
@@ -1,105 +0,0 @@ | |||||
/* | |||||
* 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.txt file. | |||||
*/ | |||||
package org.apache.tools.mail; | |||||
import java.io.BufferedReader; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.io.InputStreamReader; | |||||
/** | |||||
* A wrapper around the raw input from the SMTP server that assembles multi line | |||||
* responses into a single String. <p> | |||||
* | |||||
* The same rules used here would apply to FTP and other Telnet based protocols | |||||
* as well.</p> | |||||
* | |||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||||
*/ | |||||
public class SmtpResponseReader | |||||
{ | |||||
protected BufferedReader reader = null; | |||||
private StringBuffer result = new StringBuffer(); | |||||
/** | |||||
* Wrap this input stream. | |||||
* | |||||
* @param in Description of Parameter | |||||
*/ | |||||
public SmtpResponseReader( InputStream in ) | |||||
{ | |||||
reader = new BufferedReader( new InputStreamReader( in ) ); | |||||
} | |||||
/** | |||||
* Read until the server indicates that the response is complete. | |||||
* | |||||
* @return Responsecode (3 digits) + Blank + Text from all response line | |||||
* concatenated (with blanks replacing the \r\n sequences). | |||||
* @exception IOException Description of Exception | |||||
*/ | |||||
public String getResponse() | |||||
throws IOException | |||||
{ | |||||
result.setLength( 0 ); | |||||
String line = reader.readLine(); | |||||
if( line != null && line.length() >= 3 ) | |||||
{ | |||||
result.append( line.substring( 0, 3 ) ); | |||||
result.append( " " ); | |||||
} | |||||
while( line != null ) | |||||
{ | |||||
append( line ); | |||||
if( !hasMoreLines( line ) ) | |||||
{ | |||||
break; | |||||
} | |||||
line = reader.readLine(); | |||||
} | |||||
return result.toString().trim(); | |||||
} | |||||
/** | |||||
* Closes the underlying stream. | |||||
* | |||||
* @exception IOException Description of Exception | |||||
*/ | |||||
public void close() | |||||
throws IOException | |||||
{ | |||||
reader.close(); | |||||
} | |||||
/** | |||||
* Should we expect more input? | |||||
* | |||||
* @param line Description of Parameter | |||||
* @return Description of the Returned Value | |||||
*/ | |||||
protected boolean hasMoreLines( String line ) | |||||
{ | |||||
return line.length() > 3 && line.charAt( 3 ) == '-'; | |||||
} | |||||
/** | |||||
* Append the text from this line of the resonse. | |||||
* | |||||
* @param line Description of Parameter | |||||
*/ | |||||
private void append( String line ) | |||||
{ | |||||
if( line.length() > 4 ) | |||||
{ | |||||
result.append( line.substring( 4 ) ); | |||||
result.append( " " ); | |||||
} | |||||
} | |||||
} |
@@ -1,409 +0,0 @@ | |||||
/* | |||||
* 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.txt file. | |||||
*/ | |||||
package org.apache.tools.ant.taskdefs; | |||||
import java.io.BufferedInputStream; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.PrintStream; | |||||
import java.util.ArrayList; | |||||
import java.util.Iterator; | |||||
import java.util.StringTokenizer; | |||||
import org.apache.myrmidon.api.TaskException; | |||||
import org.apache.tools.ant.Task; | |||||
import org.apache.tools.mail.MailMessage; | |||||
/** | |||||
* A task to send SMTP email. <p> | |||||
* | |||||
* | |||||
* <tableborder="1" cellpadding="3" cellspacing="0"> | |||||
* | |||||
* <trbgcolor="#CCCCFF"> | |||||
* | |||||
* <th> | |||||
* Attribute | |||||
* </th> | |||||
* | |||||
* <th> | |||||
* Description | |||||
* </th> | |||||
* | |||||
* <th> | |||||
* Required | |||||
* </th> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* from | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Email address of sender. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Yes | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* mailhost | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Host name of the mail server. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* No, default to "localhost" | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* toList | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Comma-separated list of recipients. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Yes | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* subject | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Email subject line. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* No | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* files | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Filename(s) of text to send in the body of the email. Multiple files | |||||
* are comma-separated. | |||||
* </td> | |||||
* | |||||
* <tdrowspan="2"> | |||||
* One of these two attributes | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* message | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Message to send inthe body of the email. | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* | |||||
* </table> | |||||
* | |||||
* <tr> | |||||
* | |||||
* <td> | |||||
* includefilenames | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* Includes filenames before file contents when set to true. | |||||
* </td> | |||||
* | |||||
* <td> | |||||
* No, default is <I>false</I> | |||||
* </td> | |||||
* | |||||
* </tr> | |||||
* <p> | |||||
* | |||||
* | |||||
* | |||||
* @author glenn_twiggs@bmc.com | |||||
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||||
*/ | |||||
public class SendEmail extends Task | |||||
{ | |||||
private String mailhost = "localhost"; | |||||
private int mailport = MailMessage.DEFAULT_PORT; | |||||
private ArrayList files = new ArrayList(); | |||||
/** | |||||
* failure flag | |||||
*/ | |||||
private boolean failOnError = true; | |||||
private String from; | |||||
private boolean includefilenames; | |||||
private String message; | |||||
private String subject; | |||||
private String toList; | |||||
/** | |||||
* Creates new SendEmail | |||||
*/ | |||||
public SendEmail() | |||||
{ | |||||
} | |||||
/** | |||||
* Sets the FailOnError attribute of the MimeMail object | |||||
* | |||||
* @param failOnError The new FailOnError value | |||||
* @since 1.5 | |||||
*/ | |||||
public void setFailOnError( boolean failOnError ) | |||||
{ | |||||
this.failOnError = failOnError; | |||||
} | |||||
/** | |||||
* Sets the file parameter of this build task. | |||||
* | |||||
* @param filenames Filenames to include as the message body of this email. | |||||
*/ | |||||
public void setFiles( String filenames ) | |||||
throws TaskException | |||||
{ | |||||
StringTokenizer t = new StringTokenizer( filenames, ", " ); | |||||
while( t.hasMoreTokens() ) | |||||
{ | |||||
files.add( resolveFile( t.nextToken() ) ); | |||||
} | |||||
} | |||||
/** | |||||
* Sets the from parameter of this build task. | |||||
* | |||||
* @param from Email address of sender. | |||||
*/ | |||||
public void setFrom( String from ) | |||||
{ | |||||
this.from = from; | |||||
} | |||||
/** | |||||
* Sets Includefilenames attribute | |||||
* | |||||
* @param includefilenames Set to true if file names are to be included. | |||||
* @since 1.5 | |||||
*/ | |||||
public void setIncludefilenames( boolean includefilenames ) | |||||
{ | |||||
this.includefilenames = includefilenames; | |||||
} | |||||
/** | |||||
* Sets the mailhost parameter of this build task. | |||||
* | |||||
* @param mailhost Mail host name. | |||||
*/ | |||||
public void setMailhost( String mailhost ) | |||||
{ | |||||
this.mailhost = mailhost; | |||||
} | |||||
/** | |||||
* Sets the mailport parameter of this build task. | |||||
* | |||||
* @param value mail port name. | |||||
*/ | |||||
public void setMailport( Integer value ) | |||||
{ | |||||
this.mailport = value.intValue(); | |||||
} | |||||
/** | |||||
* Sets the message parameter of this build task. | |||||
* | |||||
* @param message Message body of this email. | |||||
*/ | |||||
public void setMessage( String message ) | |||||
{ | |||||
this.message = message; | |||||
} | |||||
/** | |||||
* Sets the subject parameter of this build task. | |||||
* | |||||
* @param subject Subject of this email. | |||||
*/ | |||||
public void setSubject( String subject ) | |||||
{ | |||||
this.subject = subject; | |||||
} | |||||
/** | |||||
* Sets the toList parameter of this build task. | |||||
* | |||||
* @param toList Comma-separated list of email recipient addreses. | |||||
*/ | |||||
public void setToList( String toList ) | |||||
{ | |||||
this.toList = toList; | |||||
} | |||||
/** | |||||
* Executes this build task. | |||||
* | |||||
* @throws TaskException if there is an error during task execution. | |||||
*/ | |||||
public void execute() | |||||
throws TaskException | |||||
{ | |||||
try | |||||
{ | |||||
MailMessage mailMessage = new MailMessage( mailhost ); | |||||
mailMessage.setPort( mailport ); | |||||
if( from != null ) | |||||
{ | |||||
mailMessage.from( from ); | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "Attribute \"from\" is required." ); | |||||
} | |||||
if( toList != null ) | |||||
{ | |||||
StringTokenizer t = new StringTokenizer( toList, ", ", false ); | |||||
while( t.hasMoreTokens() ) | |||||
{ | |||||
mailMessage.to( t.nextToken() ); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "Attribute \"toList\" is required." ); | |||||
} | |||||
if( subject != null ) | |||||
{ | |||||
mailMessage.setSubject( subject ); | |||||
} | |||||
if( !files.isEmpty() ) | |||||
{ | |||||
PrintStream out = mailMessage.getPrintStream(); | |||||
for( Iterator e = files.iterator(); e.hasNext(); ) | |||||
{ | |||||
File file = (File)e.next(); | |||||
if( file.exists() && file.canRead() ) | |||||
{ | |||||
int bufsize = 1024; | |||||
int length; | |||||
byte[] buf = new byte[ bufsize ]; | |||||
if( includefilenames ) | |||||
{ | |||||
String filename = file.getName(); | |||||
int filenamelength = filename.length(); | |||||
out.println( filename ); | |||||
for( int star = 0; star < filenamelength; star++ ) | |||||
{ | |||||
out.print( '=' ); | |||||
} | |||||
out.println(); | |||||
} | |||||
BufferedInputStream in = null; | |||||
try | |||||
{ | |||||
in = new BufferedInputStream( | |||||
new FileInputStream( file ), bufsize ); | |||||
while( ( length = in.read( buf, 0, bufsize ) ) != -1 ) | |||||
{ | |||||
out.write( buf, 0, length ); | |||||
} | |||||
if( includefilenames ) | |||||
{ | |||||
out.println(); | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
if( in != null ) | |||||
{ | |||||
try | |||||
{ | |||||
in.close(); | |||||
} | |||||
catch( IOException ioe ) | |||||
{ | |||||
} | |||||
} | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "File \"" + file.getName() | |||||
+ "\" does not exist or is not readable." ); | |||||
} | |||||
} | |||||
} | |||||
else if( message != null ) | |||||
{ | |||||
PrintStream out = mailMessage.getPrintStream(); | |||||
out.print( message ); | |||||
} | |||||
else | |||||
{ | |||||
throw new TaskException( "Attribute \"file\" or \"message\" is required." ); | |||||
} | |||||
getLogger().info( "Sending email" ); | |||||
mailMessage.sendAndClose(); | |||||
} | |||||
catch( IOException ioe ) | |||||
{ | |||||
String err = "IO error sending mail " + ioe.toString(); | |||||
if( failOnError ) | |||||
{ | |||||
throw new TaskException( err, ioe ); | |||||
} | |||||
else | |||||
{ | |||||
getLogger().error( err ); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,535 +0,0 @@ | |||||
/* | |||||
* 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.txt file. | |||||
*/ | |||||
package org.apache.tools.mail; | |||||
import java.io.BufferedOutputStream; | |||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
import java.io.PrintStream; | |||||
import java.net.InetAddress; | |||||
import java.net.Socket; | |||||
import java.util.ArrayList; | |||||
import java.util.Enumeration; | |||||
import java.util.Hashtable; | |||||
import java.util.Iterator; | |||||
/** | |||||
* A class to help send SMTP email. This class is an improvement on the | |||||
* sun.net.smtp.SmtpClient class found in the JDK. This version has extra | |||||
* functionality, and can be used with JVMs that did not extend from the JDK. | |||||
* It's not as robust as the JavaMail Standard Extension classes, but it's | |||||
* easier to use and easier to install, and has an Open Source license. <p> | |||||
* | |||||
* It can be used like this: <blockquote><pre> | |||||
* String mailhost = "localhost"; // or another mail host | |||||
* String from = "Mail Message Servlet <MailMessage@server.com>"; | |||||
* String to = "to@you.com"; | |||||
* String cc1 = "cc1@you.com"; | |||||
* String cc2 = "cc2@you.com"; | |||||
* String bcc = "bcc@you.com"; | |||||
* | |||||
* MailMessage msg = new MailMessage(mailhost); | |||||
* msg.setPort(25); | |||||
* msg.from(from); | |||||
* msg.to(to); | |||||
* msg.cc(cc1); | |||||
* msg.cc(cc2); | |||||
* msg.bcc(bcc); | |||||
* msg.setSubject("Test subject"); | |||||
* PrintStream out = msg.getPrintStream(); | |||||
* | |||||
* Iterator enum = req.getParameterNames(); | |||||
* while (enum.hasNext()) { | |||||
* String name = (String)enum.next(); | |||||
* String value = req.getParameter(name); | |||||
* out.println(name + " = " + value); | |||||
* } | |||||
* | |||||
* msg.sendAndClose(); | |||||
* </pre></blockquote> <p> | |||||
* | |||||
* Be sure to set the from address, then set the recepient addresses, then set | |||||
* the subject and other headers, then get the PrintStream, then write the | |||||
* message, and finally send and close. The class does minimal error checking | |||||
* internally; it counts on the mail host to complain if there's any | |||||
* malformatted input or out of order execution. <p> | |||||
* | |||||
* An attachment mechanism based on RFC 1521 could be implemented on top of this | |||||
* class. In the meanwhile, JavaMail is the best solution for sending email with | |||||
* attachments. <p> | |||||
* | |||||
* Still to do: | |||||
* <ul> | |||||
* <li> Figure out how to close the connection in case of error | |||||
* </ul> | |||||
* | |||||
* | |||||
* @author Jason Hunter | |||||
* @version 1.1, 2000/03/19, added angle brackets to address, helps some servers | |||||
* version 1.0, 1999/12/29 | |||||
*/ | |||||
public class MailMessage | |||||
{ | |||||
/** | |||||
* default port for SMTP: 25 | |||||
*/ | |||||
public final static int DEFAULT_PORT = 25; | |||||
/** | |||||
* host port for the mail server | |||||
*/ | |||||
private int port = DEFAULT_PORT; | |||||
/** | |||||
* list of email addresses to cc to | |||||
*/ | |||||
private ArrayList cc; | |||||
/** | |||||
* sender email address | |||||
*/ | |||||
private String from; | |||||
/** | |||||
* headers to send in the mail | |||||
*/ | |||||
private Hashtable headers; | |||||
/** | |||||
* host name for the mail server | |||||
*/ | |||||
private String host; | |||||
private SmtpResponseReader in; | |||||
private MailPrintStream out; | |||||
private Socket socket; | |||||
/** | |||||
* list of email addresses to send to | |||||
*/ | |||||
private ArrayList to; | |||||
/** | |||||
* Constructs a new MailMessage to send an email. Use localhost as the mail | |||||
* server. | |||||
* | |||||
* @exception IOException if there's any problem contacting the mail server | |||||
*/ | |||||
public MailMessage() | |||||
throws IOException | |||||
{ | |||||
this( "localhost" ); | |||||
} | |||||
/** | |||||
* Constructs a new MailMessage to send an email. Use the given host as the | |||||
* mail server. | |||||
* | |||||
* @param host the mail server to use | |||||
* @exception IOException if there's any problem contacting the mail server | |||||
*/ | |||||
public MailMessage( String host ) | |||||
throws IOException | |||||
{ | |||||
this.host = host; | |||||
to = new ArrayList(); | |||||
cc = new ArrayList(); | |||||
headers = new Hashtable(); | |||||
setHeader( "X-Mailer", "org.apache.tools.mail.MailMessage (jakarta.apache.org)" ); | |||||
connect(); | |||||
sendHelo(); | |||||
} | |||||
// Make a limited attempt to extract a sanitized email address | |||||
// Prefer text in <brackets>, ignore anything in (parentheses) | |||||
static String sanitizeAddress( String s ) | |||||
{ | |||||
int paramDepth = 0; | |||||
int start = 0; | |||||
int end = 0; | |||||
int len = s.length(); | |||||
for( int i = 0; i < len; i++ ) | |||||
{ | |||||
char c = s.charAt( i ); | |||||
if( c == '(' ) | |||||
{ | |||||
paramDepth++; | |||||
if( start == 0 ) | |||||
{ | |||||
end = i;// support "address (name)" | |||||
} | |||||
} | |||||
else if( c == ')' ) | |||||
{ | |||||
paramDepth--; | |||||
if( end == 0 ) | |||||
{ | |||||
start = i + 1;// support "(name) address" | |||||
} | |||||
} | |||||
else if( paramDepth == 0 && c == '<' ) | |||||
{ | |||||
start = i + 1; | |||||
} | |||||
else if( paramDepth == 0 && c == '>' ) | |||||
{ | |||||
end = i; | |||||
} | |||||
} | |||||
if( end == 0 ) | |||||
{ | |||||
end = len; | |||||
} | |||||
return s.substring( start, end ); | |||||
} | |||||
/** | |||||
* Sets the named header to the given value. RFC 822 provides the rules for | |||||
* what text may constitute a header name and value. | |||||
* | |||||
* @param name The new Header value | |||||
* @param value The new Header value | |||||
*/ | |||||
public void setHeader( String name, String value ) | |||||
{ | |||||
// Blindly trust the user doesn't set any invalid headers | |||||
headers.put( name, value ); | |||||
} | |||||
/** | |||||
* Set the port to connect to the SMTP host. | |||||
* | |||||
* @param port the port to use for connection. | |||||
* @see #DEFAULT_PORT | |||||
*/ | |||||
public void setPort( int port ) | |||||
{ | |||||
this.port = port; | |||||
} | |||||
/** | |||||
* Sets the subject of the mail message. Actually sets the "Subject" header. | |||||
* | |||||
* @param subj The new Subject value | |||||
*/ | |||||
public void setSubject( String subj ) | |||||
{ | |||||
headers.put( "Subject", subj ); | |||||
} | |||||
/** | |||||
* Returns a PrintStream that can be used to write the body of the message. | |||||
* A stream is used since email bodies are byte-oriented. A writer could be | |||||
* wrapped on top if necessary for internationalization. | |||||
* | |||||
* @return The PrintStream value | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public PrintStream getPrintStream() | |||||
throws IOException | |||||
{ | |||||
setFromHeader(); | |||||
setToHeader(); | |||||
setCcHeader(); | |||||
sendData(); | |||||
flushHeaders(); | |||||
return out; | |||||
} | |||||
/** | |||||
* Sets the bcc address. Does NOT set any header since it's a *blind* copy. | |||||
* This method may be called multiple times. | |||||
* | |||||
* @param bcc Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void bcc( String bcc ) | |||||
throws IOException | |||||
{ | |||||
sendRcpt( bcc ); | |||||
// No need to keep track of Bcc'd addresses | |||||
} | |||||
/** | |||||
* Sets the cc address. Also sets the "Cc" header. This method may be called | |||||
* multiple times. | |||||
* | |||||
* @param cc Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void cc( String cc ) | |||||
throws IOException | |||||
{ | |||||
sendRcpt( cc ); | |||||
this.cc.add( cc ); | |||||
} | |||||
/** | |||||
* Sets the from address. Also sets the "From" header. This method should be | |||||
* called only once. | |||||
* | |||||
* @param from Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void from( String from ) | |||||
throws IOException | |||||
{ | |||||
sendFrom( from ); | |||||
this.from = from; | |||||
} | |||||
/** | |||||
* Sends the message and closes the connection to the server. The | |||||
* MailMessage object cannot be reused. | |||||
* | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void sendAndClose() | |||||
throws IOException | |||||
{ | |||||
sendDot(); | |||||
sendQuit(); | |||||
disconnect(); | |||||
} | |||||
/** | |||||
* Sets the to address. Also sets the "To" header. This method may be called | |||||
* multiple times. | |||||
* | |||||
* @param to Description of Parameter | |||||
* @exception IOException if there's any problem reported by the mail server | |||||
*/ | |||||
public void to( String to ) | |||||
throws IOException | |||||
{ | |||||
sendRcpt( to ); | |||||
this.to.add( to ); | |||||
} | |||||
void setCcHeader() | |||||
{ | |||||
setHeader( "Cc", vectorToList( cc ) ); | |||||
} | |||||
void setFromHeader() | |||||
{ | |||||
setHeader( "From", from ); | |||||
} | |||||
void setToHeader() | |||||
{ | |||||
setHeader( "To", vectorToList( to ) ); | |||||
} | |||||
void getReady() | |||||
throws IOException | |||||
{ | |||||
String response = in.getResponse(); | |||||
int[] ok = {220}; | |||||
if( !isResponseOK( response, ok ) ) | |||||
{ | |||||
throw new IOException( | |||||
"Didn't get introduction from server: " + response ); | |||||
} | |||||
} | |||||
boolean isResponseOK( String response, int[] ok ) | |||||
{ | |||||
// Check that the response is one of the valid codes | |||||
for( int i = 0; i < ok.length; i++ ) | |||||
{ | |||||
if( response.startsWith( "" + ok[ i ] ) ) | |||||
{ | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
// * * * * * Raw protocol methods below here * * * * * | |||||
void connect() | |||||
throws IOException | |||||
{ | |||||
socket = new Socket( host, port ); | |||||
out = new MailPrintStream( | |||||
new BufferedOutputStream( | |||||
socket.getOutputStream() ) ); | |||||
in = new SmtpResponseReader( socket.getInputStream() ); | |||||
getReady(); | |||||
} | |||||
void disconnect() | |||||
throws IOException | |||||
{ | |||||
if( out != null ) | |||||
{ | |||||
out.close(); | |||||
} | |||||
if( in != null ) | |||||
{ | |||||
in.close(); | |||||
} | |||||
if( socket != null ) | |||||
{ | |||||
socket.close(); | |||||
} | |||||
} | |||||
void flushHeaders() | |||||
throws IOException | |||||
{ | |||||
// XXX Should I care about order here? | |||||
Enumeration e = headers.keys(); | |||||
while( e.hasMoreElements() ) | |||||
{ | |||||
String name = (String)e.nextElement(); | |||||
String value = (String)headers.get( name ); | |||||
out.println( name + ": " + value ); | |||||
} | |||||
out.println(); | |||||
out.flush(); | |||||
} | |||||
void send( String msg, int[] ok ) | |||||
throws IOException | |||||
{ | |||||
out.rawPrint( msg + "\r\n" );// raw supports <CRLF>.<CRLF> | |||||
//System.out.println("S: " + msg); | |||||
String response = in.getResponse(); | |||||
//System.out.println("R: " + response); | |||||
if( !isResponseOK( response, ok ) ) | |||||
{ | |||||
throw new IOException( | |||||
"Unexpected reply to command: " + msg + ": " + response ); | |||||
} | |||||
} | |||||
void sendData() | |||||
throws IOException | |||||
{ | |||||
int[] ok = {354}; | |||||
send( "DATA", ok ); | |||||
} | |||||
void sendDot() | |||||
throws IOException | |||||
{ | |||||
int[] ok = {250}; | |||||
send( "\r\n.", ok );// make sure dot is on new line | |||||
} | |||||
void sendFrom( String from ) | |||||
throws IOException | |||||
{ | |||||
int[] ok = {250}; | |||||
send( "MAIL FROM: " + "<" + sanitizeAddress( from ) + ">", ok ); | |||||
} | |||||
void sendHelo() | |||||
throws IOException | |||||
{ | |||||
String local = InetAddress.getLocalHost().getHostName(); | |||||
int[] ok = {250}; | |||||
send( "HELO " + local, ok ); | |||||
} | |||||
void sendQuit() | |||||
throws IOException | |||||
{ | |||||
int[] ok = {221}; | |||||
send( "QUIT", ok ); | |||||
} | |||||
void sendRcpt( String rcpt ) | |||||
throws IOException | |||||
{ | |||||
int[] ok = {250, 251}; | |||||
send( "RCPT TO: " + "<" + sanitizeAddress( rcpt ) + ">", ok ); | |||||
} | |||||
String vectorToList( ArrayList v ) | |||||
{ | |||||
StringBuffer buf = new StringBuffer(); | |||||
Iterator e = v.iterator(); | |||||
while( e.hasNext() ) | |||||
{ | |||||
buf.append( e.next() ); | |||||
if( e.hasNext() ) | |||||
{ | |||||
buf.append( ", " ); | |||||
} | |||||
} | |||||
return buf.toString(); | |||||
} | |||||
} | |||||
// This PrintStream subclass makes sure that <CRLF>. becomes <CRLF>.. | |||||
// per RFC 821. It also ensures that new lines are always \r\n. | |||||
// | |||||
class MailPrintStream extends PrintStream | |||||
{ | |||||
int lastChar; | |||||
public MailPrintStream( OutputStream out ) | |||||
{ | |||||
super( out, true );// deprecated, but email is byte-oriented | |||||
} | |||||
// Mac does \n\r, but that's tough to distinguish from Windows \r\n\r\n. | |||||
// Don't tackle that problem right now. | |||||
public void write( int b ) | |||||
{ | |||||
if( b == '\n' && lastChar != '\r' ) | |||||
{ | |||||
rawWrite( '\r' );// ensure always \r\n | |||||
rawWrite( b ); | |||||
} | |||||
else if( b == '.' && lastChar == '\n' ) | |||||
{ | |||||
rawWrite( '.' );// add extra dot | |||||
rawWrite( b ); | |||||
} | |||||
else | |||||
{ | |||||
rawWrite( b ); | |||||
} | |||||
lastChar = b; | |||||
} | |||||
public void write( byte buf[], int off, int len ) | |||||
{ | |||||
for( int i = 0; i < len; i++ ) | |||||
{ | |||||
write( buf[ off + i ] ); | |||||
} | |||||
} | |||||
void rawPrint( String s ) | |||||
{ | |||||
int len = s.length(); | |||||
for( int i = 0; i < len; i++ ) | |||||
{ | |||||
rawWrite( s.charAt( i ) ); | |||||
} | |||||
} | |||||
void rawWrite( int b ) | |||||
{ | |||||
super.write( b ); | |||||
} | |||||
} | |||||
@@ -1,105 +0,0 @@ | |||||
/* | |||||
* 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.txt file. | |||||
*/ | |||||
package org.apache.tools.mail; | |||||
import java.io.BufferedReader; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.io.InputStreamReader; | |||||
/** | |||||
* A wrapper around the raw input from the SMTP server that assembles multi line | |||||
* responses into a single String. <p> | |||||
* | |||||
* The same rules used here would apply to FTP and other Telnet based protocols | |||||
* as well.</p> | |||||
* | |||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||||
*/ | |||||
public class SmtpResponseReader | |||||
{ | |||||
protected BufferedReader reader = null; | |||||
private StringBuffer result = new StringBuffer(); | |||||
/** | |||||
* Wrap this input stream. | |||||
* | |||||
* @param in Description of Parameter | |||||
*/ | |||||
public SmtpResponseReader( InputStream in ) | |||||
{ | |||||
reader = new BufferedReader( new InputStreamReader( in ) ); | |||||
} | |||||
/** | |||||
* Read until the server indicates that the response is complete. | |||||
* | |||||
* @return Responsecode (3 digits) + Blank + Text from all response line | |||||
* concatenated (with blanks replacing the \r\n sequences). | |||||
* @exception IOException Description of Exception | |||||
*/ | |||||
public String getResponse() | |||||
throws IOException | |||||
{ | |||||
result.setLength( 0 ); | |||||
String line = reader.readLine(); | |||||
if( line != null && line.length() >= 3 ) | |||||
{ | |||||
result.append( line.substring( 0, 3 ) ); | |||||
result.append( " " ); | |||||
} | |||||
while( line != null ) | |||||
{ | |||||
append( line ); | |||||
if( !hasMoreLines( line ) ) | |||||
{ | |||||
break; | |||||
} | |||||
line = reader.readLine(); | |||||
} | |||||
return result.toString().trim(); | |||||
} | |||||
/** | |||||
* Closes the underlying stream. | |||||
* | |||||
* @exception IOException Description of Exception | |||||
*/ | |||||
public void close() | |||||
throws IOException | |||||
{ | |||||
reader.close(); | |||||
} | |||||
/** | |||||
* Should we expect more input? | |||||
* | |||||
* @param line Description of Parameter | |||||
* @return Description of the Returned Value | |||||
*/ | |||||
protected boolean hasMoreLines( String line ) | |||||
{ | |||||
return line.length() > 3 && line.charAt( 3 ) == '-'; | |||||
} | |||||
/** | |||||
* Append the text from this line of the resonse. | |||||
* | |||||
* @param line Description of Parameter | |||||
*/ | |||||
private void append( String line ) | |||||
{ | |||||
if( line.length() > 4 ) | |||||
{ | |||||
result.append( line.substring( 4 ) ); | |||||
result.append( " " ); | |||||
} | |||||
} | |||||
} |