git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274480 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -100,6 +100,13 @@ Library Dependencies</a> for more information. | |||||
| <code>auto</code>. The default value is <code>auto</code>.</td> | <code>auto</code>. The default value is <code>auto</code>.</td> | ||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">charset</td> | |||||
| <td valign="top">Character set of the email.<br> | |||||
| You can also set the charset in the message nested element.<br> | |||||
| These options are mutually exclusive.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | <tr> | ||||
| <td valign="top">subject</td> | <td valign="top">subject</td> | ||||
| <td valign="top">Email subject line.</td> | <td valign="top">Email subject line.</td> | ||||
| @@ -151,6 +158,13 @@ attributes:</p> | |||||
| <td valign="top">The content type to use for the message.</td> | <td valign="top">The content type to use for the message.</td> | ||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">charset</td> | |||||
| <td valign="top">Character set of the message<br> | |||||
| You can also set the charset as attribute of the enclosing mail task.<br> | |||||
| These options are mutually exclusive.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <p>If the <code>src</code> attribute is not specified, then text can be added | <p>If the <code>src</code> attribute is not specified, then text can be added | ||||
| @@ -187,6 +201,21 @@ the <code><message></code> element.</p> | |||||
| task will attempt to use JavaMail and fall back to UU encoding or no encoding in | task will attempt to use JavaMail and fall back to UU encoding or no encoding in | ||||
| that order depending on what support classes are available. <code>${buildname}</code> | that order depending on what support classes are available. <code>${buildname}</code> | ||||
| will be replaced with the <code>buildname</code> property's value.</p> | will be replaced with the <code>buildname</code> property's value.</p> | ||||
| <blockquote><pre> | |||||
| <property name="line2" value="some_international_message"/> | |||||
| <echo message="${line2}"/> | |||||
| <mail mailhost="somehost@xyz.com" mailport="25" subject="Test build" charset="utf-8"> | |||||
| <from address="me@myist.com"/> | |||||
| <to address="all@xyz.com" /> | |||||
| <message>some international text:${line2}</message> | |||||
| </mail> | |||||
| </pre></blockquote> | |||||
| <p>Sends an eMail from <i>me@myisp.com</i> to <i>all@xyz.com</i> with a subject of | |||||
| <i>Test Build</i>, the message body being coded in UTF-8 | |||||
| <hr> | <hr> | ||||
| <p align="center">Copyright © 2000-2003 Apache Software Foundation. All rights | <p align="center">Copyright © 2000-2003 Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * The Apache Software License, Version 1.1 | * The Apache Software License, Version 1.1 | ||||
| * | * | ||||
| * Copyright (c) 2000-2002 The Apache Software Foundation. All rights | |||||
| * Copyright (c) 2000-2003 The Apache Software Foundation. All rights | |||||
| * reserved. | * reserved. | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| @@ -76,6 +76,7 @@ import org.apache.tools.ant.types.FileSet; | |||||
| * @author ehatcher@apache.org Erik Hatcher | * @author ehatcher@apache.org Erik Hatcher | ||||
| * @author paulo.gaspar@krankikom.de Paulo Gaspar | * @author paulo.gaspar@krankikom.de Paulo Gaspar | ||||
| * @author roxspring@imapmail.org Rob Oxspring | * @author roxspring@imapmail.org Rob Oxspring | ||||
| * @author <a href="mailto:ishu@akm.ru">Aleksandr Ishutin</a> | |||||
| * @since Ant 1.5 | * @since Ant 1.5 | ||||
| * @ant.task name="mail" category="network" | * @ant.task name="mail" category="network" | ||||
| */ | */ | ||||
| @@ -132,6 +133,8 @@ public class EmailTask | |||||
| /** file list */ | /** file list */ | ||||
| private Vector files = new Vector(); | private Vector files = new Vector(); | ||||
| private Vector filesets = new Vector(); | private Vector filesets = new Vector(); | ||||
| /** Character set for MimeMailer*/ | |||||
| private String charset=null; | |||||
| /** | /** | ||||
| @@ -410,7 +413,7 @@ public class EmailTask | |||||
| autoFound = true; | autoFound = true; | ||||
| log("Using MIME mail", Project.MSG_VERBOSE); | log("Using MIME mail", Project.MSG_VERBOSE); | ||||
| } catch (Throwable e) { | } catch (Throwable e) { | ||||
| log("Failed to initialise MIME mail", Project.MSG_WARN); | |||||
| log("Failed to initialise MIME mail: "+e.getMessage(),Project.MSG_WARN); | |||||
| } | } | ||||
| } | } | ||||
| @@ -468,6 +471,15 @@ public class EmailTask | |||||
| message.setMimeType(messageMimeType); | message.setMimeType(messageMimeType); | ||||
| } | } | ||||
| } | } | ||||
| // set the character set if not done already (and required) | |||||
| if (charset != null) { | |||||
| if (message.getCharset()!=null) { | |||||
| throw new BuildException("The charset can only be " | |||||
| + "specified in one location"); | |||||
| } else { | |||||
| message.setCharset(charset); | |||||
| } | |||||
| } | |||||
| // identify which files should be attached | // identify which files should be attached | ||||
| Enumeration e = filesets.elements(); | Enumeration e = filesets.elements(); | ||||
| @@ -519,10 +531,34 @@ public class EmailTask | |||||
| if (failOnError) { | if (failOnError) { | ||||
| throw e; | throw e; | ||||
| } | } | ||||
| } | |||||
| catch(Exception e){ | |||||
| log("Failed to send email", Project.MSG_WARN); | |||||
| if (failOnError) { | |||||
| throw new BuildException(e); | |||||
| } | |||||
| } finally { | } finally { | ||||
| message = savedMessage; | message = savedMessage; | ||||
| files = savedFiles; | files = savedFiles; | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Sets the character set of mail message. | |||||
| * Will be ignored if mimeType contains ....; Charset=... substring or | |||||
| * encoding is not a <code>mime</code> | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public void setCharset(String charset) { | |||||
| this.charset = charset; | |||||
| } | |||||
| /** | |||||
| * Returns the character set of mail message. | |||||
| * | |||||
| * @return Charset of mail message. | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public String getCharset() { | |||||
| return charset; | |||||
| } | |||||
| } | } | ||||
| @@ -57,13 +57,17 @@ import java.io.BufferedReader; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.FileReader; | import java.io.FileReader; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.OutputStreamWriter; | |||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||
| import java.io.PrintWriter; | |||||
| import org.apache.tools.ant.ProjectComponent; | import org.apache.tools.ant.ProjectComponent; | ||||
| /** | /** | ||||
| * Class representing an email message. | * Class representing an email message. | ||||
| * | * | ||||
| * @author roxspring@yahoo.com Rob Oxspring | * @author roxspring@yahoo.com Rob Oxspring | ||||
| * @author <a href="mailto:ishu@akm.ru">Aleksandr Ishutin</a> | |||||
| * @since Ant 1.5 | * @since Ant 1.5 | ||||
| */ | */ | ||||
| public class Message extends ProjectComponent { | public class Message extends ProjectComponent { | ||||
| @@ -71,7 +75,7 @@ public class Message extends ProjectComponent { | |||||
| private StringBuffer buffer = new StringBuffer(); | private StringBuffer buffer = new StringBuffer(); | ||||
| private String mimeType = "text/plain"; | private String mimeType = "text/plain"; | ||||
| private boolean specified = false; | private boolean specified = false; | ||||
| private String charset=null; | |||||
| /** Creates a new empty message */ | /** Creates a new empty message */ | ||||
| public Message() { | public Message() { | ||||
| @@ -145,8 +149,13 @@ public class Message extends ProjectComponent { | |||||
| * @param out The print stream to write to | * @param out The print stream to write to | ||||
| * @throws IOException if an error occurs | * @throws IOException if an error occurs | ||||
| */ | */ | ||||
| public void print(PrintStream out) | |||||
| public void print(PrintStream ps) | |||||
| throws IOException { | throws IOException { | ||||
| // We need character encoding aware printing here. | |||||
| // So, using PrintWriter over OutputStreamWriter instead of PrintStream | |||||
| PrintWriter out = charset!=null? | |||||
| new PrintWriter(new OutputStreamWriter(ps,charset)): | |||||
| new PrintWriter(ps); | |||||
| if (messageSource != null) { | if (messageSource != null) { | ||||
| // Read message from a file | // Read message from a file | ||||
| FileReader freader = new FileReader(messageSource); | FileReader freader = new FileReader(messageSource); | ||||
| @@ -154,7 +163,6 @@ public class Message extends ProjectComponent { | |||||
| try { | try { | ||||
| BufferedReader in = new BufferedReader(freader); | BufferedReader in = new BufferedReader(freader); | ||||
| String line = null; | String line = null; | ||||
| while ((line = in.readLine()) != null) { | while ((line = in.readLine()) != null) { | ||||
| out.println(getProject().replaceProperties(line)); | out.println(getProject().replaceProperties(line)); | ||||
| } | } | ||||
| @@ -164,6 +172,7 @@ public class Message extends ProjectComponent { | |||||
| } else { | } else { | ||||
| out.println(getProject().replaceProperties(buffer.substring(0))); | out.println(getProject().replaceProperties(buffer.substring(0))); | ||||
| } | } | ||||
| out.flush(); | |||||
| } | } | ||||
| @@ -175,5 +184,22 @@ public class Message extends ProjectComponent { | |||||
| public boolean isMimeTypeSpecified() { | public boolean isMimeTypeSpecified() { | ||||
| return specified; | return specified; | ||||
| } | } | ||||
| /** | |||||
| * Sets the character set of mail message. | |||||
| * Will be ignored if mimeType contains ....; Charset=... substring. | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public void setCharset(String charset) { | |||||
| this.charset = charset; | |||||
| } | |||||
| /** | |||||
| * Returns the charset of mail message. | |||||
| * | |||||
| * @return Charset of mail message. | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public String getCharset() { | |||||
| return charset; | |||||
| } | |||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * The Apache Software License, Version 1.1 | * The Apache Software License, Version 1.1 | ||||
| * | * | ||||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||||
| * Copyright (c) 2002-2003 The Apache Software Foundation. All rights | |||||
| * reserved. | * reserved. | ||||
| * | * | ||||
| * Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
| @@ -53,16 +53,23 @@ | |||||
| */ | */ | ||||
| package org.apache.tools.ant.taskdefs.email; | package org.apache.tools.ant.taskdefs.email; | ||||
| import java.io.ByteArrayInputStream; | |||||
| import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.InputStream; | |||||
| import java.io.OutputStream; | |||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||
| import java.io.UnsupportedEncodingException; | import java.io.UnsupportedEncodingException; | ||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import java.util.Properties; | import java.util.Properties; | ||||
| import java.util.StringTokenizer; | |||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import javax.activation.DataHandler; | import javax.activation.DataHandler; | ||||
| import javax.activation.FileDataSource; | import javax.activation.FileDataSource; | ||||
| import javax.mail.Message; | import javax.mail.Message; | ||||
| import javax.mail.MessagingException; | import javax.mail.MessagingException; | ||||
| import javax.mail.Session; | import javax.mail.Session; | ||||
| @@ -72,17 +79,75 @@ import javax.mail.internet.InternetAddress; | |||||
| import javax.mail.internet.MimeBodyPart; | import javax.mail.internet.MimeBodyPart; | ||||
| import javax.mail.internet.MimeMessage; | import javax.mail.internet.MimeMessage; | ||||
| import javax.mail.internet.MimeMultipart; | import javax.mail.internet.MimeMultipart; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| /** | /** | ||||
| * Uses the JavaMail classes to send Mime format email. | * Uses the JavaMail classes to send Mime format email. | ||||
| * | * | ||||
| * @author roxspring@yahoo.com Rob Oxspring | * @author roxspring@yahoo.com Rob Oxspring | ||||
| * @author <a href="mailto:ishu@akm.ru">Aleksandr Ishutin</a> | |||||
| * @since Ant 1.5 | * @since Ant 1.5 | ||||
| */ | */ | ||||
| class MimeMailer extends Mailer { | class MimeMailer extends Mailer { | ||||
| /** Sends the email */ | |||||
| public void send() { | |||||
| // Default character set | |||||
| private static final String defaultCharset = System.getProperty("file.encoding"); | |||||
| // To work poperly with national charsets we have to use | |||||
| // implementation of interface javax.activation.DataSource | |||||
| /** | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| class StringDataSource implements javax.activation.DataSource { | |||||
| private String data=null; | |||||
| private String type=null; | |||||
| private String charset = null; | |||||
| private ByteArrayOutputStream out; | |||||
| public InputStream getInputStream() throws IOException { | |||||
| if(data == null && out == null) | |||||
| throw new IOException("No data"); | |||||
| else { | |||||
| if(out!=null) { | |||||
| data=(data!=null)?data.concat(out.toString(charset)):out.toString(charset); | |||||
| out=null; | |||||
| } | |||||
| return new ByteArrayInputStream(data.getBytes(charset)); | |||||
| } | |||||
| } | |||||
| public OutputStream getOutputStream() throws IOException { | |||||
| if(out==null) { | |||||
| out=new ByteArrayOutputStream(); | |||||
| } | |||||
| return out; | |||||
| } | |||||
| public void setContentType(String type) { | |||||
| this.type=type.toLowerCase(); | |||||
| } | |||||
| public String getContentType() { | |||||
| if(type !=null && type.indexOf("charset")>0 && type.startsWith("text/")) | |||||
| return type; | |||||
| // Must be like "text/plain; charset=windows-1251" | |||||
| return type!=null?type.concat("; charset=".concat(charset)): | |||||
| "text/plain".concat("; charset=".concat(charset)); | |||||
| } | |||||
| public String getName() { | |||||
| return "StringDataSource"; | |||||
| } | |||||
| public void setCharset(String charset) { | |||||
| this.charset = charset; | |||||
| } | |||||
| public String getCharset() { | |||||
| return charset; | |||||
| } | |||||
| } | |||||
| /** Sends the email */ | |||||
| public void send() { | |||||
| try { | try { | ||||
| Properties props = new Properties(); | Properties props = new Properties(); | ||||
| @@ -113,20 +178,38 @@ class MimeMailer extends Mailer { | |||||
| msg.setRecipients(Message.RecipientType.BCC, | msg.setRecipients(Message.RecipientType.BCC, | ||||
| internetAddresses(bccList)); | internetAddresses(bccList)); | ||||
| if (subject != null) { | |||||
| msg.setSubject(subject); | |||||
| // Choosing character set of the mail message | |||||
| // First: looking it from MimeType | |||||
| String charset = parseCharSetFromMimeType(message.getMimeType()); | |||||
| if(charset!=null) { | |||||
| // Assign/reassign message charset from MimeType | |||||
| message.setCharset(charset); | |||||
| } | |||||
| // Next: looking if charset having explict definition | |||||
| else { | |||||
| charset = message.getCharset(); | |||||
| if(charset==null) { | |||||
| // Using default | |||||
| charset=defaultCharset; | |||||
| message.setCharset(charset); | |||||
| } | |||||
| } | } | ||||
| msg.addHeader("Date", getDate()); | |||||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||||
| PrintStream out = new PrintStream(baos); | |||||
| // Using javax.activation.DataSource paradigm | |||||
| StringDataSource sds = new StringDataSource(); | |||||
| sds.setContentType(message.getMimeType()); | |||||
| sds.setCharset(charset); | |||||
| if (subject != null) | |||||
| msg.setSubject(subject,charset); | |||||
| msg.addHeader("Date", getDate()); | |||||
| PrintStream out = new PrintStream(sds.getOutputStream()); | |||||
| message.print(out); | message.print(out); | ||||
| out.close(); | out.close(); | ||||
| MimeBodyPart textbody = new MimeBodyPart(); | MimeBodyPart textbody = new MimeBodyPart(); | ||||
| textbody.setContent(baos.toString(), message.getMimeType()); | |||||
| textbody.setDataHandler(new DataHandler(sds)); | |||||
| attachments.addBodyPart(textbody); | attachments.addBodyPart(textbody); | ||||
| Enumeration e = files.elements(); | Enumeration e = files.elements(); | ||||
| @@ -177,5 +260,15 @@ class MimeMailer extends Mailer { | |||||
| return addrs; | return addrs; | ||||
| } | } | ||||
| private String parseCharSetFromMimeType(String type){ | |||||
| int pos; | |||||
| if(type==null || (pos=type.indexOf("charset"))<0) | |||||
| return null; | |||||
| // Assuming mime type in form "text/XXXX; charset=XXXXXX" | |||||
| StringTokenizer token = new StringTokenizer(type.substring(pos),"=; "); | |||||
| token.nextToken();// Skip 'charset=' | |||||
| return token.nextToken(); | |||||
| } | |||||
| } | } | ||||