package railo.runtime.tag;
import javax.mail.internet.InternetAddress;
import railo.commons.io.res.Resource;
import railo.commons.io.res.util.ResourceUtil;
import railo.commons.lang.StringUtil;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.ext.tag.BodyTagImpl;
import railo.runtime.net.mail.MailException;
import railo.runtime.net.mail.MailPart;
import railo.runtime.net.smtp.SMTPClient;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
// TODO test proxy
/**
*
* Sends e-mail messages by an SMTP server.
*
*
*
**/
public final class Mail extends BodyTagImpl {
/** Specifies the query column to use when you group sets of records together to send as an e-mail
** message. For example, if you send a set of billing statements to customers, you might group on
** "Customer_ID." The group attribute, which is case sensitive, eliminates adjacent duplicates when the
** data is sorted by the specified field. See the Usage section for exceptions. */
private String group;
/** Boolean indicating whether to group with regard to case or not. The default value is YES;
** case is considered while grouping. If the query attribute specifies a query object that was generated
** by a case-insensitive SQL query, set the groupCaseSensitive attribute to NO to keep the recordset
** intact. */
private boolean groupcasesensitive;
/** The name of the cfquery from which to draw data for message(s) to send. Specify this
** attribute to send more than one mail message, or to send the results of a query within a message. */
private String query;
/** Specifies the maximum number of e-mail messages to send. */
private double maxrows;
/** Specifies the row in the query to start from. */
private double startrow;
//private railo.runtime.mail.Mail mail=new railo.runtime.mail.Mail();
private SMTPClient smtp=new SMTPClient();
private railo.runtime.net.mail.MailPart part=null;//new railo.runtime.mail.MailPart("UTF-8");
private String charset;
private int priority;
private boolean remove;
@Override
public void release() {
super.release();
// do not clear because spooler
//mail=new railo.runtime.mail.Mail();
smtp=new SMTPClient();
part=null;//new railo.runtime.mail.MailPart("UTF-8");
group=null;
groupcasesensitive=false;
query=null;
maxrows=0d;
startrow=0d;
charset=null;
remove=false;
}
/**
* @param remove the remove to set
*/
public void setRemove(boolean remove) {
this.remove = remove;
}
/**
* @param proxyserver The proxyserver to set.
* @throws ApplicationException
*/
public void setProxyserver(String proxyserver) throws ApplicationException {
try {
smtp.getProxyData().setServer(proxyserver);
} catch (Exception e) {
throw new ApplicationException("attribute [proxyserver] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value proxyport
* The port number on the proxy server from which the object is requested. Default is 80. When
* used with resolveURL, the URLs of retrieved documents that specify a port number are automatically
* resolved to preserve links in the retrieved document.
* @param proxyport value to set
* @throws ApplicationException
**/
public void setProxyport(double proxyport) throws ApplicationException {
try {
smtp.getProxyData().setPort((int)proxyport);
} catch (Exception e) {
throw new ApplicationException("attribute [proxyport] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value username
* When required by a proxy server, a valid username.
* @param proxyuser value to set
* @throws ApplicationException
**/
public void setProxyuser(String proxyuser) throws ApplicationException {
try {
smtp.getProxyData().setUsername(proxyuser);
} catch (Exception e) {
throw new ApplicationException("attribute [proxyuser] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value password
* When required by a proxy server, a valid password.
* @param proxypassword value to set
* @throws ApplicationException
**/
public void setProxypassword(String proxypassword) throws ApplicationException {
try {
smtp.getProxyData().setPassword(proxypassword);
} catch (Exception e) {
throw new ApplicationException("attribute [proxypassword] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value from
* The sender of the e-mail message.
* @param strForm value to set
* @throws PageException
**/
public void setFrom(Object from) throws PageException {
if(StringUtil.isEmpty(from)) return;
try {
smtp.setFrom(from);
} catch (Exception e) {
throw Caster.toPageException(e);
}
}
/** set the value to
* The name of the e-mail message recipient.
* @param strTo value to set
* @throws ApplicationException
**/
public void setTo(Object to) throws ApplicationException {
if(StringUtil.isEmpty(to)) return;
try {
smtp.addTo(to);
} catch (Exception e) {
throw new ApplicationException("attribute [to] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value cc
* Indicates addresses to copy the e-mail message to; "cc" stands for "carbon copy."
* @param strCc value to set
* @throws ApplicationException
**/
public void setCc(Object cc) throws ApplicationException {
if(StringUtil.isEmpty(cc)) return;
try {
smtp.addCC(cc);
} catch (Exception e) {
throw new ApplicationException("attribute [cc] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value bcc
* Indicates addresses to copy the e-mail message to, without listing them in the message header.
* "bcc" stands for "blind carbon copy."
* @param strBcc value to set
* @throws ApplicationException
**/
public void setBcc(Object bcc) throws ApplicationException {
if(StringUtil.isEmpty(bcc)) return;
try {
smtp.addBCC(bcc);
} catch (Exception e) {
throw new ApplicationException("attribute [bcc] of the tag [mail] is invalid",e.getMessage());
}
}
/**
* @param strFailto The failto to set.
* @throws ApplicationException
*/
public void setFailto(Object failto) throws ApplicationException {
if(StringUtil.isEmpty(failto)) return;
try {
smtp.addFailTo(failto);
} catch (Exception e) {
throw new ApplicationException("attribute [failto] of the tag [mail] is invalid",e.getMessage());
}
}
/**
* @param strReplyto The replyto to set.
* @throws ApplicationException
*/
public void setReplyto(Object replyto) throws ApplicationException {
if(StringUtil.isEmpty(replyto)) return;
try {
smtp.addReplyTo(replyto);
} catch (Exception e) {
throw new ApplicationException("attribute [replyto] of the tag [mail] is invalid",e.getMessage());
}
}
/** set the value type
* Specifies extended type attributes for the message.
* @param type value to set
* @throws ApplicationException
**/
public void setType(String type) throws ApplicationException {
type=type.toLowerCase().trim();
if(type.equals("text/plain") || type.equals("plain") || type.equals("text"))
getPart().isHTML(false);
//mail.setType(railo.runtime.mail.Mail.TYPE_TEXT);
else if(type.equals("text/html") || type.equals("html") || type.equals("htm"))
getPart().isHTML(true);
else
throw new ApplicationException("attribute type of tag mail has an invalid values","valid values are [plain,text,html] but value is now ["+type+"]");
//throw new ApplicationException(("invalid type "+type);
}
/** set the value subject
* The subject of the mail message. This field may be driven dynamically on
* a message-by-message basis
* @param subject value to set
**/
public void setSubject(String subject) {
smtp.setSubject(subject);
}
/**
* @param username The username to set.
*/
public void setUsername(String username) {
smtp.setUsername(username);
}
/**
* @param password The password to set.
*/
public void setPassword(String password) {
smtp.setPassword(password);
}
/** set the value mimeattach
* Specifies the path of the file to be attached to the e-mail message. An attached file
* is MIME-encoded.
* @param strMimeattach value to set
* @param type mimetype of the file
* @param contentID
* @param disposition
* @throws PageException
**/
public void setMimeattach(String strMimeattach, String type, String disposition, String contentID,boolean removeAfterSend) throws PageException {
Resource file=ResourceUtil.toResourceNotExisting(pageContext,strMimeattach);
pageContext.getConfig().getSecurityManager().checkFileLocation(file);
if(!file.exists())
throw new ApplicationException("can't attach file "+strMimeattach+", this file doesn't exist");
smtp.addAttachment(file,type,disposition,contentID,removeAfterSend);
}
public void setMimeattach(String strMimeattach) throws PageException {
setMimeattach(strMimeattach, "", null, null,false);
}
/**
* @param spoolenable The spoolenable to set.
*/
public void setSpoolenable(boolean spoolenable) {
smtp.setSpoolenable(spoolenable);
}
/** set the value server
* @param strServer value to set
* @throws PageException
**/
public void setServer(String strServer) throws PageException {
smtp.setHost(strServer);
}
/** set the value mailerid
* @param mailerid value to set
**/
public void setMailerid(String mailerid) {
smtp.setXMailer(mailerid);
}
/** set the value port
* The TCP/IP port on which the SMTP server listens for requests. This is normally 25.
* @param port value to set
**/
public void setPort(double port) {
smtp.setPort((int)port);
}
/**
* @param wraptext The wraptext to set.
*/
public void setWraptext(double wraptext) {
getPart().setWraptext((int)wraptext);
}
/** set the value timeout
* The number of seconds to wait before timing out the connection to the SMTP server.
* @param timeout value to set
**/
public void setTimeout(double timeout) {
smtp.setTimeout((int)(timeout*1000));
}
/**
* @param charset The charset to set.
*/
public void setCharset(String charset) {
this.charset=charset;
}
/** set the value group
* Specifies the query column to use when you group sets of records together to send as an e-mail
* message. For example, if you send a set of billing statements to customers, you might group on
* "Customer_ID." The group attribute, which is case sensitive, eliminates adjacent duplicates when the
* data is sorted by the specified field. See the Usage section for exceptions.
* @param group value to set
**/
public void setGroup(String group) {
this.group=group;
}
/** set the value groupcasesensitive
* Boolean indicating whether to group with regard to case or not. The default value is YES;
* case is considered while grouping. If the query attribute specifies a query object that was generated
* by a case-insensitive SQL query, set the groupCaseSensitive attribute to NO to keep the recordset
* intact.
* @param groupcasesensitive value to set
**/
public void setGroupcasesensitive(boolean groupcasesensitive) {
this.groupcasesensitive=groupcasesensitive;
}
/** set the value query
* The name of the cfquery from which to draw data for message(s) to send. Specify this
* attribute to send more than one mail message, or to send the results of a query within a message.
* @param query value to set
**/
public void setQuery(String query) {
this.query=query;
}
/** set the value maxrows
* Specifies the maximum number of e-mail messages to send.
* @param maxrows value to set
**/
public void setMaxrows(double maxrows) {
this.maxrows=maxrows;
}
public void setTls(boolean tls) {
smtp.setTLS(tls);
}
public void setUsetls(boolean tls) {
smtp.setTLS(tls);
}
public void setStarttls(boolean tls) {
smtp.setTLS(tls);
}
public void setSsl(boolean ssl) {
smtp.setSSL(ssl);
}
public void setUsessl(boolean ssl) {
smtp.setSSL(ssl);
}
public void setSecure(boolean ssl) {
smtp.setSSL(ssl);
}
public void setPriority(String strPriority) throws ExpressionException {
strPriority=strPriority.trim().toLowerCase();
boolean valid=true;
if(Decision.isNumeric(strPriority)) {
int p=Caster.toIntValue(strPriority,-1);
if(p<1 || p>5)valid=false;
else this.priority=p;
}
else {
if("highest".equals(strPriority))priority=1;
else if("urgent".equals(strPriority))priority=1;
else if("high".equals(strPriority))priority=2;
else if("normal".equals(strPriority))priority=3;
else if("low".equals(strPriority))priority=4;
else if("lowest".equals(strPriority))priority=5;
else if("non-urgent".equals(strPriority))priority=5;
else if("none-urgent".equals(strPriority))priority=5;
else valid=false;
}
if(!valid)throw new ExpressionException("the value of attribute priority is invalid ["+strPriority+"], " +
"the value should be an integer between [1-5] or " +
"one of the following [highest,urgent,high,normal,low,lowest,non-urgent]");
}
/** set the value startrow
* Specifies the row in the query to start from.
* @param startrow value to set
**/
public void setStartrow(double startrow) {
this.startrow=startrow;
}
/**
* @param part
*/
public void addPart(MailPart part) {
String type = part.getType();
if(StringUtil.isEmpty(part.getCharset())) part.setCharset(getCharset());
if(type!=null && (type.equals("text/plain") || type.equals("plain") || type.equals("text"))){
part.isHTML(false);
addClassicBodyPart(part);
}
else if(type!=null && (type.equals("text/html") || type.equals("html") || type.equals("htm"))){
part.isHTML(true);
addClassicBodyPart(part);
}
else {
addBodyPart(part);
}
}
// this was not supported in prior releases
private void addBodyPart(MailPart part) {
smtp.setPart(part);
}
/**
* @param part
*/
private void addClassicBodyPart(MailPart part) {
if(part.isHTML()) {
if(!smtp.hasHTMLText())smtp.setHTMLText(part.getBody(), part.getCharset());
}
else {
if(!smtp.hasPlainText())smtp.setPlainText(part.getBody(), part.getCharset());
}
}
@Override
public int doStartTag() throws ApplicationException {
if(isEmpty(smtp.getTos()) && isEmpty(smtp.getCcs()) && isEmpty(smtp.getBccs()))
throw new ApplicationException("One of the following attribtues must be defined [to, cc, bcc]");
return EVAL_BODY_BUFFERED;
}
private boolean isEmpty(InternetAddress[] addrs) {
return addrs==null || addrs.length==0;
}
@Override
public void doInitBody() {
}
@Override
public int doAfterBody() {
getPart().setBody(bodyContent.getString());
smtp.setCharset(getCharset());
getPart().setCharset(getCharset());
addClassicBodyPart(getPart());
return SKIP_BODY;
}
@Override
public int doEndTag() throws PageException {
smtp.setTimeZone(pageContext.getTimeZone());
try {
smtp.send(pageContext.getConfig());
}
catch (MailException e) {
throw Caster.toPageException(e);
}
return EVAL_PAGE;
}
/**
* sets a mail param
* @param type
* @param file
* @param name
* @param value
* @param contentID
* @param disposition
* @throws PageException
*/
public void setParam(String type, String file, String name, String value, String disposition, String contentID,Boolean oRemoveAfterSend) throws PageException {
if(file!=null){
boolean removeAfterSend=(oRemoveAfterSend==null)?remove:oRemoveAfterSend.booleanValue();
setMimeattach(file,type,disposition,contentID,removeAfterSend);
}
else {
if(name.equalsIgnoreCase("bcc")) setBcc(value);
else if(name.equalsIgnoreCase("cc")) setCc(value);
else if(name.equalsIgnoreCase("charset")) setCharset(value);
else if(name.equalsIgnoreCase("failto")) setFailto(value);
else if(name.equalsIgnoreCase("from")) setFrom(value);
else if(name.equalsIgnoreCase("mailerid")) setMailerid(value);
else if(name.equalsIgnoreCase("mimeattach"))setMimeattach(value);
else if(name.equalsIgnoreCase("priority")) setPriority(value);
else if(name.equalsIgnoreCase("replyto")) setReplyto(value);
else if(name.equalsIgnoreCase("subject")) setSubject(value);
else if(name.equalsIgnoreCase("to")) setTo(value);
else smtp.addHeader(name,value);
}
}
private railo.runtime.net.mail.MailPart getPart() {
if(part==null)part=new railo.runtime.net.mail.MailPart(pageContext.getConfig().getMailDefaultEncoding());
return part;
}
/**
* @return the charset
*/
public String getCharset() {
if(charset==null)charset=pageContext.getConfig().getMailDefaultEncoding();
return charset;
}
}