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( " " ); | |||
| } | |||
| } | |||
| } | |||