diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/mail/MailMessage.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/mail/MailMessage.java | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/mail/MailMessage.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/mail/MailMessage.java new file mode 100644 index 00000000..b4173a96 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/mail/MailMessage.java @@ -0,0 +1,526 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* + * The original version of this class was donated by Jason Hunter, + * who wrote the class as part of the com.oreilly.servlet + * package for his book "Java Servlet Programming" (O'Reilly). + * See http://www.servlets.com. + * + */ + +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.Enumeration; +import java.util.Vector; + +/** + * 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(); + * + * Enumeration enum = req.getParameterNames(); + * while (enum.hasMoreElements()) { + * String name = (String)enum.nextElement(); + * String value = req.getParameter(name); + * out.println(name + " = " + value); + * } + * + * msg.sendAndClose(); + * </pre></blockquote> + * <p> + * Be sure to set the from address, then set the recipient + * 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> + * + * @version 1.1, 2000/03/19, added angle brackets to address, helps some servers + * version 1.0, 1999/12/29 + */ +public class MailMessage { + + /** default mailhost */ + public static final String DEFAULT_HOST = "localhost"; + + /** default port for SMTP: 25 */ + public static final int DEFAULT_PORT = 25; + + /** host name for the mail server */ + private String host; + + /** host port for the mail server */ + private int port = DEFAULT_PORT; + + /** sender email address */ + private String from; + + /** list of email addresses to reply to */ + private Vector replyto; + + /** list of email addresses to send to */ + private Vector to; + + /** list of email addresses to cc to */ + private Vector cc; + + /** headers to send in the mail */ + private Vector headersKeys; + private Vector headersValues; + + private MailPrintStream out; + + private SmtpResponseReader in; + + private Socket socket; + private static final int OK_READY = 220; + private static final int OK_HELO = 250; + private static final int OK_FROM = 250; + private static final int OK_RCPT_1 = 250; + private static final int OK_RCPT_2 = 251; + private static final int OK_DATA = 354; + private static final int OK_DOT = 250; + private static final int OK_QUIT = 221; + + /** + * Constructs a new MailMessage to send an email. + * Use localhost as the mail server with port 25. + * + * @exception IOException if there's any problem contacting the mail server + */ + public MailMessage() throws IOException { + this(DEFAULT_HOST, DEFAULT_PORT); + } + + /** + * Constructs a new MailMessage to send an email. + * Use the given host as the mail server with port 25. + * + * @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, DEFAULT_PORT); + } + + /** + * Constructs a new MailMessage to send an email. + * Use the given host and port as the mail server. + * + * @param host the mail server to use + * @param port the port to connect to + * @exception IOException if there's any problem contacting the mail server + */ + public MailMessage(String host, int port) throws IOException { + this.port = port; + this.host = host; + replyto = new Vector(); + to = new Vector(); + cc = new Vector(); + headersKeys = new Vector(); + headersValues = new Vector(); + connect(); + sendHelo(); + } + + /** + * 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 from address. Also sets the "From" header. This method should + * be called only once. + * @param from the from address + * @exception IOException if there's any problem reported by the mail server + */ + public void from(String from) throws IOException { + sendFrom(from); + this.from = from; + } + + /** + * Sets the replyto address + * This method may be + * called multiple times. + * @param rto the replyto address + * + */ + public void replyto(String rto) { + this.replyto.addElement(rto); + } + + /** + * Sets the to address. Also sets the "To" header. This method may be + * called multiple times. + * + * @param to the to address + * @exception IOException if there's any problem reported by the mail server + */ + public void to(String to) throws IOException { + sendRcpt(to); + this.to.addElement(to); + } + + /** + * Sets the cc address. Also sets the "Cc" header. This method may be + * called multiple times. + * + * @param cc the cc address + * @exception IOException if there's any problem reported by the mail server + */ + public void cc(String cc) throws IOException { + sendRcpt(cc); + this.cc.addElement(cc); + } + + /** + * Sets the bcc address. Does NOT set any header since it's a *blind* copy. + * This method may be called multiple times. + * + * @param bcc the bcc address + * @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 subject of the mail message. Actually sets the "Subject" + * header. + * @param subj the subject of the mail message + */ + public void setSubject(String subj) { + setHeader("Subject", subj); + } + + /** + * 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 name of the header + * @param value contents of the header + */ + public void setHeader(String name, String value) { + // Blindly trust the user doesn't set any invalid headers + headersKeys.add(name); + headersValues.add(value); + } + + /** + * 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 can + * be wrapped on top if necessary for internationalization. + * This is actually done in Message.java + * + * @return a printstream containing the data and the headers of the email + * @exception IOException if there's any problem reported by the mail server + * @see org.apache.tools.ant.taskdefs.email.Message + */ + public PrintStream getPrintStream() throws IOException { + setFromHeader(); + setReplyToHeader(); + setToHeader(); + setCcHeader(); + setHeader("X-Mailer", "org.apache.tools.mail.MailMessage (ant.apache.org)"); + sendData(); + flushHeaders(); + return out; + } + + + // RFC 822 s4.1: "From:" header must be sent + // We rely on error checking by the MTA + void setFromHeader() { + setHeader("From", from); + } + + // RFC 822 s4.1: "Reply-To:" header is optional + void setReplyToHeader() { + if (!replyto.isEmpty()) { + setHeader("Reply-To", vectorToList(replyto)); + } + } + + void setToHeader() { + if (!to.isEmpty()) { + setHeader("To", vectorToList(to)); + } + } + + void setCcHeader() { + if (!cc.isEmpty()) { + setHeader("Cc", vectorToList(cc)); + } + } + + String vectorToList(Vector v) { + StringBuffer buf = new StringBuffer(); + Enumeration e = v.elements(); + while (e.hasMoreElements()) { + buf.append(e.nextElement()); + if (e.hasMoreElements()) { + buf.append(", "); + } + } + return buf.toString(); + } + + void flushHeaders() throws IOException { + // RFC 822 s4.1: + // "Header fields are NOT required to occur in any particular order, + // except that the message body MUST occur AFTER the headers" + // (the same section specifies a recommended order, which we ignore) + final int size = headersKeys.size(); + for (int i = 0; i < size; i++) { + String name = (String) headersKeys.elementAt(i); + String value = (String) headersValues.elementAt(i); + out.println(name + ": " + value); + } + out.println(); + out.flush(); + } + + /** + * 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 { + try { + sendDot(); + sendQuit(); + } finally { + disconnect(); + } + } + + // 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); + } + + // * * * * * 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 getReady() throws IOException { + String response = in.getResponse(); + int[] ok = {OK_READY}; + if (!isResponseOK(response, ok)) { + throw new IOException( + "Didn't get introduction from server: " + response); + } + } + void sendHelo() throws IOException { + String local = InetAddress.getLocalHost().getHostName(); + int[] ok = {OK_HELO}; + send("HELO " + local, ok); + } + void sendFrom(String from) throws IOException { + int[] ok = {OK_FROM}; + send("MAIL FROM: " + "<" + sanitizeAddress(from) + ">", ok); + } + void sendRcpt(String rcpt) throws IOException { + int[] ok = {OK_RCPT_1, OK_RCPT_2}; + send("RCPT TO: " + "<" + sanitizeAddress(rcpt) + ">", ok); + } + + void sendData() throws IOException { + int[] ok = {OK_DATA}; + send("DATA", ok); + } + + void sendDot() throws IOException { + int[] ok = {OK_DOT}; + send("\r\n.", ok); // make sure dot is on new line + } + + void sendQuit() throws IOException { + int[] ok = {OK_QUIT}; + try { + send("QUIT", ok); + } catch (IOException e) { + throw new ErrorInQuitException(e); + } + } + + void send(String msg, int[] ok) throws IOException { + out.rawPrint(msg + "\r\n"); // raw supports <CRLF>.<CRLF> + String response = in.getResponse(); + if (!isResponseOK(response, ok)) { + throw new IOException("Unexpected reply to command: " + + msg + ": " + 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; + } + + void disconnect() throws IOException { + if (out != null) { + out.close(); + } + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // ignore + } + } + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + // ignore + } + } + } +} + +/** + * 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 { + + private 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 rawWrite(int b) { + super.write(b); + } + + void rawPrint(String s) { + int len = s.length(); + for (int i = 0; i < len; i++) { + rawWrite(s.charAt(i)); + } + } +} + |