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