001    package railo.runtime.tag;
002    
003    
004    import javax.mail.internet.InternetAddress;
005    
006    import railo.commons.io.res.Resource;
007    import railo.commons.io.res.util.ResourceUtil;
008    import railo.commons.lang.StringUtil;
009    import railo.runtime.config.ConfigImpl;
010    import railo.runtime.exp.ApplicationException;
011    import railo.runtime.exp.ExpressionException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.ext.tag.BodyTagImpl;
014    import railo.runtime.net.mail.MailException;
015    import railo.runtime.net.mail.MailPart;
016    import railo.runtime.net.smtp.SMTPClient;
017    import railo.runtime.op.Caster;
018    import railo.runtime.op.Decision;
019    // TODO test proxy
020    /**
021     * 
022    * Sends e-mail messages by an SMTP server.
023    *
024    *
025    *
026    **/
027    public final class Mail extends BodyTagImpl {
028    
029            /** Specifies the query column to use when you group sets of records together to send as an e-mail 
030            **              message. For example, if you send a set of billing statements to customers, you might group on 
031            **              "Customer_ID." The group attribute, which is case sensitive, eliminates adjacent duplicates when the 
032            **              data is sorted by the specified field. See the Usage section for exceptions. */
033            private String group;
034    
035            /** Boolean indicating whether to group with regard to case or not. The default value is YES; 
036            **              case is considered while grouping. If the query attribute specifies a query object that was generated 
037            **              by a case-insensitive SQL query, set the groupCaseSensitive attribute to NO to keep the recordset 
038            **              intact. */
039            private boolean groupcasesensitive;
040    
041            /** The name of the cfquery from which to draw data for message(s) to send. Specify this 
042            **              attribute to send more than one mail message, or to send the results of a query within a message. */
043            private String query;
044    
045            /** Specifies the maximum number of e-mail messages to send. */
046            private double maxrows;
047    
048            /** Specifies the row in the query to start from. */
049            private double startrow;
050        
051    
052    
053            //private railo.runtime.mail.Mail mail=new railo.runtime.mail.Mail();
054            private SMTPClient smtp=new SMTPClient();
055            private railo.runtime.net.mail.MailPart part=null;//new railo.runtime.mail.MailPart("UTF-8");
056    
057            private String charset;
058    
059            private int priority;
060    
061            private boolean remove;
062            
063            
064    
065            /**
066            * @see javax.servlet.jsp.tagext.Tag#release()
067            */
068            public void release()   {
069                    super.release();
070    //       do not clear because spooler
071            //mail=new railo.runtime.mail.Mail();   
072                    smtp=new SMTPClient();
073            part=null;//new railo.runtime.mail.MailPart("UTF-8");
074                    group=null;
075                    groupcasesensitive=false;
076                    query=null;
077                    maxrows=0d;
078                    startrow=0d;
079                    charset=null;
080                    remove=false;
081            }
082            
083            
084            /**
085             * @param remove the remove to set
086             */
087            public void setRemove(boolean remove) {
088                    this.remove = remove;
089            }
090    
091    
092            /**
093         * @param proxyserver The proxyserver to set.
094             * @throws ApplicationException 
095         */
096        public void setProxyserver(String proxyserver) throws ApplicationException {
097                    try {
098                            smtp.getProxyData().setServer(proxyserver);
099                    } catch (Exception e) {
100                            throw new ApplicationException("attribute [proxyserver] of the tag [mail] is invalid",e.getMessage());
101                    }
102        }
103            
104            /** set the value proxyport
105            *  The port number on the proxy server from which the object is requested. Default is 80. When 
106            *       used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 
107            *       resolved to preserve links in the retrieved document.
108            * @param proxyport value to set
109             * @throws ApplicationException 
110            **/
111            public void setProxyport(double proxyport) throws ApplicationException  {
112                    try {
113                            smtp.getProxyData().setPort((int)proxyport);
114                    } catch (Exception e) {
115                            throw new ApplicationException("attribute [proxyport] of the tag [mail] is invalid",e.getMessage());
116                    }
117            }
118    
119            /** set the value username
120            *  When required by a proxy server, a valid username.
121            * @param proxyuser value to set
122             * @throws ApplicationException 
123            **/
124            public void setProxyuser(String proxyuser) throws ApplicationException  {
125                    try {
126                            smtp.getProxyData().setUsername(proxyuser);
127                    } catch (Exception e) {
128                            throw new ApplicationException("attribute [proxyuser] of the tag [mail] is invalid",e.getMessage());
129                    }
130            }
131    
132        
133            /** set the value password
134            *  When required by a proxy server, a valid password.
135            * @param proxypassword value to set
136             * @throws ApplicationException 
137            **/
138            public void setProxypassword(String proxypassword) throws ApplicationException  {
139                    try {
140                            smtp.getProxyData().setPassword(proxypassword);
141                    } catch (Exception e) {
142                            throw new ApplicationException("attribute [proxypassword] of the tag [mail] is invalid",e.getMessage());
143                    }
144            }
145    
146            
147    
148            /** set the value from
149            *  The sender of the e-mail message.
150            * @param strForm value to set
151             * @throws PageException 
152            **/
153            public void setFrom(Object from) throws PageException   {
154                    if(StringUtil.isEmpty(from)) return;
155                    try {
156                            smtp.setFrom(from);
157                    } catch (Exception e) {
158                            throw Caster.toPageException(e);
159                    }
160            }
161    
162            /** set the value to
163            *  The name of the e-mail message recipient.
164            * @param strTo value to set
165             * @throws ApplicationException
166            **/
167            public void setTo(Object to) throws ApplicationException        {
168                    if(StringUtil.isEmpty(to)) return;
169                    try {
170                            smtp.addTo(to);
171                    } catch (Exception e) {
172                            throw new ApplicationException("attribute [to] of the tag [mail] is invalid",e.getMessage());
173                    }
174            }
175    
176            /** set the value cc
177            *  Indicates addresses to copy the e-mail message to; "cc" stands for "carbon copy."
178            * @param strCc value to set
179             * @throws ApplicationException
180            **/
181            public void setCc(Object cc) throws ApplicationException        {
182                    if(StringUtil.isEmpty(cc)) return;
183                    try {
184                            smtp.addCC(cc);
185                    } catch (Exception e) {
186                            throw new ApplicationException("attribute [cc] of the tag [mail] is invalid",e.getMessage());
187                    }
188            }
189    
190    
191    
192            /** set the value bcc
193            *  Indicates addresses to copy the e-mail message to, without listing them in the message header. 
194            *               "bcc" stands for "blind carbon copy."
195            * @param strBcc value to set
196             * @throws ApplicationException
197            **/
198            public void setBcc(Object bcc) throws ApplicationException      {
199                    if(StringUtil.isEmpty(bcc)) return;
200                    try {
201                            smtp.addBCC(bcc);
202                    } catch (Exception e) {
203                            throw new ApplicationException("attribute [bcc] of the tag [mail] is invalid",e.getMessage());
204                    }
205            }       
206            
207            /**
208             * @param strFailto The failto to set.
209             * @throws ApplicationException
210             */
211            public void setFailto(Object failto) throws ApplicationException {
212                    if(StringUtil.isEmpty(failto)) return;
213                    try {
214                            smtp.addFailTo(failto);
215                    } catch (Exception e) {
216                            throw new ApplicationException("attribute [failto] of the tag [mail] is invalid",e.getMessage());
217                    }
218            }
219            /**
220             * @param strReplyto The replyto to set.
221             * @throws ApplicationException
222             */
223            public void setReplyto(Object replyto) throws ApplicationException {
224                    if(StringUtil.isEmpty(replyto)) return;
225                    try {
226                            smtp.addReplyTo(replyto);
227                    } catch (Exception e) {
228                            throw new ApplicationException("attribute [replyto] of the tag [mail] is invalid",e.getMessage());
229                    }
230            }
231            
232            /** set the value type
233            *  Specifies extended type attributes for the message.
234            * @param type value to set
235             * @throws ApplicationException
236            **/
237            public void setType(String type) throws ApplicationException    {
238                    type=type.toLowerCase().trim();
239                    if(type.equals("text/plain") || type.equals("plain") || type.equals("text"))
240                        getPart().isHTML(false);
241                        //mail.setType(railo.runtime.mail.Mail.TYPE_TEXT);
242                    else if(type.equals("text/html") || type.equals("html") || type.equals("htm"))
243                            getPart().isHTML(true);
244                    else
245                            throw new ApplicationException("attribute type of tag mail has a invalid values","valid values are [plain,text,html] but value is now ["+type+"]");
246                            //throw new ApplicationException(("invalid type "+type);
247            }
248    
249            /** set the value subject
250            *  The subject of the mail message. This field may be driven dynamically on 
251            *               a message-by-message basis
252            * @param subject value to set
253            **/
254            public void setSubject(String subject)  {
255                    smtp.setSubject(subject);
256            }
257            /**
258             * @param username The username to set.
259             */
260            public void setUsername(String username) {
261                    smtp.setUsername(username);
262            }
263            /**
264             * @param password The password to set.
265             */
266            public void setPassword(String password) {
267                    smtp.setPassword(password);
268            }
269            
270            /** set the value mimeattach
271            *  Specifies the path of the file to be attached to the e-mail message. An attached file 
272            *               is MIME-encoded.
273            * @param strMimeattach value to set
274             * @param type mimetype of the file
275             * @param contentID 
276             * @param disposition 
277             * @throws PageException 
278            **/
279            public void setMimeattach(String strMimeattach, String type, String disposition, String contentID,boolean removeAfterSend) throws PageException {
280                    Resource file=ResourceUtil.toResourceNotExisting(pageContext,strMimeattach);
281            pageContext.getConfig().getSecurityManager().checkFileLocation(file);
282                    if(!file.exists())
283                            throw new ApplicationException("can't attach file "+strMimeattach+", this file doesn't exist");
284                    
285    
286            smtp.addAttachment(file,type,disposition,contentID,removeAfterSend);
287                    
288            }
289            public void setMimeattach(String strMimeattach) throws PageException    {
290                    setMimeattach(strMimeattach, "", null, null,false);
291            }
292            
293            /**
294             * @param spoolenable The spoolenable to set.
295             */
296            public void setSpoolenable(boolean spoolenable) {
297                    smtp.setSpoolenable(spoolenable);
298            }
299            
300            /** set the value server
301            * @param strServer value to set
302             * @throws PageException 
303            **/
304            public void setServer(String strServer) throws PageException {
305                    smtp.setHost(strServer);
306            }
307     
308            /** set the value mailerid
309            * @param mailerid value to set
310            **/
311            public void setMailerid(String mailerid)        {
312                    smtp.setXMailer(mailerid);
313            }
314            
315            /** set the value port
316            *  The TCP/IP port on which the SMTP server listens for requests. This is normally 25.
317            * @param port value to set
318            **/
319            public void setPort(double port)        {
320                    smtp.setPort((int)port);
321            }
322            
323            /**
324             * @param wraptext The wraptext to set.
325             */
326            public void setWraptext(double wraptext) {
327                    getPart().setWraptext((int)wraptext);
328            }
329    
330            /** set the value timeout
331            *  The number of seconds to wait before timing out the connection to the SMTP server.
332            * @param timeout value to set
333            **/
334            public void setTimeout(double timeout)  {
335                    smtp.setTimeout((int)(timeout*1000));
336            }
337            
338            /**
339             * @param charset The charset to set.
340             */
341            public void setCharset(String charset) {
342                    this.charset=charset;
343            }
344    
345            /** set the value group
346            *  Specifies the query column to use when you group sets of records together to send as an e-mail 
347            *               message. For example, if you send a set of billing statements to customers, you might group on 
348            *               "Customer_ID." The group attribute, which is case sensitive, eliminates adjacent duplicates when the 
349            *               data is sorted by the specified field. See the Usage section for exceptions.
350            * @param group value to set
351            **/
352            public void setGroup(String group)      {
353                    this.group=group;
354            }
355    
356            /** set the value groupcasesensitive
357            *  Boolean indicating whether to group with regard to case or not. The default value is YES; 
358            *               case is considered while grouping. If the query attribute specifies a query object that was generated 
359            *               by a case-insensitive SQL query, set the groupCaseSensitive attribute to NO to keep the recordset 
360            *               intact.
361            * @param groupcasesensitive value to set
362            **/
363            public void setGroupcasesensitive(boolean groupcasesensitive)   {
364                    this.groupcasesensitive=groupcasesensitive;
365            }
366    
367            /** set the value query
368            *  The name of the cfquery from which to draw data for message(s) to send. Specify this 
369            *               attribute to send more than one mail message, or to send the results of a query within a message.
370            * @param query value to set
371            **/
372            public void setQuery(String query)      {
373                    this.query=query;
374            }
375    
376            /** set the value maxrows
377            *  Specifies the maximum number of e-mail messages to send.
378            * @param maxrows value to set
379            **/
380            public void setMaxrows(double maxrows)  {
381                    this.maxrows=maxrows;
382            }
383            
384    
385            public void setTls(boolean tls) {
386                    smtp.setTLS(tls);
387            }       
388            
389            public void setUsetls(boolean tls)      {
390                    smtp.setTLS(tls);
391            }       
392            
393            public void setStarttls(boolean tls)    {
394                    smtp.setTLS(tls);
395            }
396    
397            public void setSsl(boolean ssl) {
398                    smtp.setSSL(ssl);
399            }
400    
401            public void setUsessl(boolean ssl)      {
402                    smtp.setSSL(ssl);
403            }
404    
405            public void setSecure(boolean ssl)      {
406                    smtp.setSSL(ssl);
407            }
408            public void setPriority(String strPriority) throws ExpressionException  {
409                    strPriority=strPriority.trim().toLowerCase();
410                    boolean valid=true;
411                    if(Decision.isNumeric(strPriority)) {
412                            int p=Caster.toIntValue(strPriority,-1);
413                            if(p<1 || p>5)valid=false;
414                            else this.priority=p;
415                    }
416                    else {
417                            if("highest".equals(strPriority))priority=1;
418                            else if("urgent".equals(strPriority))priority=1;
419                            else if("high".equals(strPriority))priority=2;
420                            else if("normal".equals(strPriority))priority=3;
421                            else if("low".equals(strPriority))priority=4;
422                            else if("lowest".equals(strPriority))priority=5;
423                            else if("non-urgent".equals(strPriority))priority=5;
424                            else if("none-urgent".equals(strPriority))priority=5;
425                            else valid=false;
426                    }
427                    
428                    if(!valid)throw new ExpressionException("the value of attribute priority is invalid ["+strPriority+"], " +
429                                    "the value should be an integer between [1-5] or " +
430                                    "one of the following [highest,urgent,high,normal,low,lowest,non-urgent]");
431                    
432            }
433    
434            /** set the value startrow
435            *  Specifies the row in the query to start from.
436            * @param startrow value to set
437            **/
438            public void setStartrow(double startrow)        {
439                    this.startrow=startrow;
440            }
441    
442        /**
443         * @param part
444         */
445        public void addPart(MailPart part) {
446            String type = part.getType();
447                    if(StringUtil.isEmpty(part.getCharset())) part.setCharset(getCharset());
448                    if(type!=null && (type.equals("text/plain") || type.equals("plain") || type.equals("text"))){
449                            part.isHTML(false);
450                            addClassicBodyPart(part);
451                    }
452                    else if(type!=null && (type.equals("text/html") || type.equals("html") || type.equals("htm"))){
453                            part.isHTML(true);
454                            addClassicBodyPart(part);
455                    }   
456                    else {
457                            addBodyPart(part);
458                    }
459        }
460            
461        // this was not supported in prior releases
462            private void addBodyPart(MailPart part) {
463                    smtp.setPart(part);
464            }
465    
466            /**
467         * @param part
468         */
469        private void addClassicBodyPart(MailPart part) {
470            if(part.isHTML()) {
471                if(!smtp.hasHTMLText())smtp.setHTMLText(part.getBody(), part.getCharset());
472            }
473            else {
474                if(!smtp.hasPlainText())smtp.setPlainText(part.getBody(), part.getCharset());
475            }
476        }
477    
478    
479        /**
480            * @throws ApplicationException 
481         * @see javax.servlet.jsp.tagext.Tag#doStartTag()
482            */
483            public int doStartTag() throws ApplicationException     {
484                    if(isEmpty(smtp.getTos()) && isEmpty(smtp.getCcs()) && isEmpty(smtp.getBccs())) 
485                            throw new ApplicationException("One of the following attribtues must be defined [to, cc, bcc]");
486                            
487                    return EVAL_BODY_BUFFERED;
488            }
489    
490            private boolean isEmpty(InternetAddress[] addrs) {
491                    return addrs==null || addrs.length==0;
492            }
493    
494    
495            /**
496            * @see javax.servlet.jsp.tagext.BodyTag#doInitBody()
497            */
498            public void doInitBody()        {
499                    
500            }
501    
502            /**
503            * @see javax.servlet.jsp.tagext.BodyTag#doAfterBody()
504            */
505            public int doAfterBody()        {
506                    getPart().setBody(bodyContent.getString());
507                    smtp.setCharset(getCharset());
508                    getPart().setCharset(getCharset());
509                    addClassicBodyPart(getPart());
510                    return SKIP_BODY;
511            }
512            
513            /**
514             * @see javax.servlet.jsp.tagext.Tag#doEndTag()
515            */
516            public int doEndTag() throws PageException      {
517                    smtp.setTimeZone(pageContext.getTimeZone());
518                    try {
519                            smtp.send((ConfigImpl) pageContext.getConfig());
520                    } 
521                    catch (MailException e) {
522                            throw Caster.toPageException(e);
523                    }
524                    return EVAL_PAGE;
525            }
526    
527            /**
528             * sets a mail param
529             * @param type
530             * @param file
531             * @param name
532             * @param value
533             * @param contentID 
534             * @param disposition 
535             * @throws PageException 
536             */
537            public void setParam(String type, String file, String name, String value, String disposition, String contentID,Boolean oRemoveAfterSend) throws PageException {
538                    if(file!=null){
539                            boolean removeAfterSend=(oRemoveAfterSend==null)?remove:oRemoveAfterSend.booleanValue();
540                                    
541                            setMimeattach(file,type,disposition,contentID,removeAfterSend);
542                    }
543                    else {
544                            if(name.equalsIgnoreCase("bcc"))                        setBcc(value);
545                            else if(name.equalsIgnoreCase("cc"))            setCc(value);
546                            else if(name.equalsIgnoreCase("charset"))       setCharset(value);
547                            else if(name.equalsIgnoreCase("failto"))        setFailto(value);
548                            else if(name.equalsIgnoreCase("from"))          setFrom(value);
549                            else if(name.equalsIgnoreCase("mailerid"))      setMailerid(value);
550                            else if(name.equalsIgnoreCase("mimeattach"))setMimeattach(value);
551                            else if(name.equalsIgnoreCase("priority"))      setPriority(value);
552                            else if(name.equalsIgnoreCase("replyto"))       setReplyto(value);
553                            else if(name.equalsIgnoreCase("subject"))       setSubject(value);
554                            else if(name.equalsIgnoreCase("to"))            setTo(value);
555                            
556                            else smtp.addHeader(name,value);
557                    }
558            }       
559            
560            private railo.runtime.net.mail.MailPart getPart() {
561                    if(part==null)part=new railo.runtime.net.mail.MailPart(pageContext.getConfig().getMailDefaultEncoding());
562                    return part;
563            }
564    
565    
566            /**
567             * @return the charset
568             */
569            public String getCharset() {
570                    if(charset==null)charset=pageContext.getConfig().getMailDefaultEncoding();
571                    return charset;
572            }
573    }