package railo.runtime.net.mail; import java.io.UnsupportedEncodingException; import java.net.IDN; import java.util.ArrayList; import java.util.Iterator; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeUtility; import railo.commons.lang.StringUtil; import railo.runtime.exp.PageException; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.type.Array; import railo.runtime.type.Struct; import railo.runtime.type.util.ListUtil; public final class MailUtil { public static String encode(String text,String encoding) throws UnsupportedEncodingException { //print.ln(StringUtil.changeCharset(text,encoding)); return MimeUtility.encodeText(text,encoding,"Q"); } public static String decode(String text) throws UnsupportedEncodingException { return MimeUtility.decodeText(text); } public static InternetAddress toInternetAddress(Object emails) throws MailException, UnsupportedEncodingException, PageException { if ( emails instanceof String ) return parseEmail( emails ); InternetAddress[] addresses = toInternetAddresses( emails ); if ( addresses != null && addresses.length > 0 ) return addresses[0]; return null; } public static InternetAddress[] toInternetAddresses(Object emails) throws MailException, UnsupportedEncodingException, PageException { if (emails instanceof String ) return fromList((String) emails); else if ( Decision.isArray(emails) ) return fromArray(Caster.toArray(emails)); else if ( Decision.isStruct(emails) ) return new InternetAddress[]{ fromStruct(Caster.toStruct(emails)) }; else throw new MailException("e-mail defintions must be one of the following types [string,array,struct], not ["+emails.getClass().getName()+"]"); } private static InternetAddress[] fromArray(Array array) throws MailException, PageException, UnsupportedEncodingException { Iterator it = array.valueIterator(); Object el; ArrayList<InternetAddress> pairs = new ArrayList(); while(it.hasNext()){ el=it.next(); if ( Decision.isStruct( el ) ) { pairs.add( fromStruct(Caster.toStruct(el)) ); } else { InternetAddress addr = parseEmail( Caster.toString(el) ); if ( addr != null ) pairs.add( addr ); } } return pairs.toArray( new InternetAddress[ pairs.size() ] ); } private static InternetAddress fromStruct( Struct sct ) throws MailException, UnsupportedEncodingException { String name = Caster.toString(sct.get("label",null),null); if ( name == null ) name=Caster.toString(sct.get("name",null),null); String email = Caster.toString(sct.get("email",null),null); if ( email == null ) email = Caster.toString(sct.get("e-mail",null),null); if ( email == null ) email = Caster.toString(sct.get("mail",null),null); if( StringUtil.isEmpty(email) ) throw new MailException("missing e-mail definition in struct"); if(name==null) name=""; return new InternetAddress( email, name ); } private static InternetAddress[] fromList( String strEmails ) { if ( StringUtil.isEmpty( strEmails, true ) ) return new InternetAddress[0]; Array raw = ListUtil.listWithQuotesToArray(strEmails, ",;", "\""); Iterator<Object> it = raw.valueIterator(); ArrayList<InternetAddress> al = new ArrayList(); while( it.hasNext() ) { InternetAddress addr = parseEmail( it.next() ); if( addr != null ) al.add( addr ); } return al.toArray( new InternetAddress[ al.size() ] ); } /** * returns true if the passed value is a in valid email address format * @param value * @return */ public static boolean isValidEmail( Object value ) { InternetAddress addr = parseEmail( value ); if ( addr != null ) { String address = addr.getAddress(); if ( address.contains( ".." ) ) return false; int pos = address.indexOf( '@' ); if ( pos < 1 || pos == address.length() - 1 ) return false; String local = address.substring(0, pos); String domain = address.substring(pos + 1); if ( domain.charAt( 0 ) == '.' || local.charAt( 0 ) == '.' || local.charAt( local.length() - 1 ) == '.' ) return false; pos = domain.lastIndexOf( '.' ); if ( pos > 0 && pos < domain.length() - 2 ) // test TLD to be at least 2 chars all alpha characters return StringUtil.isAllAlpha( domain.substring( pos + 1 ) ); } return false; } /** * returns an InternetAddress object or null if the parsing fails. to be be used in multiple places. * @param value * @return */ public static InternetAddress parseEmail( Object value ) { String str = Caster.toString( value, "" ); if ( str.indexOf( '@' ) > -1 ) { try { InternetAddress addr = new InternetAddress( str ); fixIDN( addr ); return addr; } catch ( AddressException ex ) {} } return null; } /** * converts IDN to ASCII if needed * @param addr */ public static void fixIDN( InternetAddress addr ) { String address = addr.getAddress(); int pos = address.indexOf( '@' ); if ( pos > 0 && pos < address.length() - 1 ) { String domain = address.substring( pos + 1 ); if ( !StringUtil.isAscii( domain ) ) { domain = IDN.toASCII( domain ); addr.setAddress( address.substring( 0, pos ) + "@" + domain ); } } } }