001 package railo.runtime.net.mail; 002 003 import java.io.UnsupportedEncodingException; 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 import java.util.regex.Matcher; 007 import java.util.regex.Pattern; 008 009 import javax.mail.internet.AddressException; 010 import javax.mail.internet.InternetAddress; 011 012 import railo.commons.lang.StringUtil; 013 import railo.runtime.exp.PageException; 014 import railo.runtime.op.Caster; 015 import railo.runtime.op.Decision; 016 import railo.runtime.type.Array; 017 import railo.runtime.type.List; 018 import railo.runtime.type.Struct; 019 020 021 /** 022 * represent a email name pair 023 */ 024 public final class EmailNamePair { 025 026 private static final short EMAIL=0; 027 private static final short EMAIL_NAME=1; 028 private static final short NAME_EMAIL=2; 029 030 private String email=""; 031 private String name=""; 032 private static Pattern[] patterns=new Pattern[8]; 033 private static short[] pairType=new short[8]; 034 035 static { 036 String email="([\\w\\._\\-\\%\\+\\'\\!\\#\\$\\%\\&]*@[\\w\\._\\-]*)"; 037 patterns[0]=Pattern.compile("^"+email+"\\s*\\(([^\\)]+)\\)$"); 038 patterns[1]=Pattern.compile("^"+email+"\\s*:\\s*(.+)$"); 039 patterns[2]=Pattern.compile("^([^:]+)\\s*:\\s*"+email+"$"); 040 patterns[3]=Pattern.compile("^\"([^\"]+)\"[\\s]<[\\s]*"+email+"[\\s]*>$"); 041 patterns[4]=Pattern.compile("^'([^']+)'[\\s]<[\\s]*"+email+"[\\s]*>$"); 042 patterns[5]=Pattern.compile("^([^<]+)<[\\s]*"+email+"[\\s]*>$"); 043 patterns[6]=Pattern.compile("^<[\\s]*"+email+"[\\s]*>$"); 044 patterns[7]=Pattern.compile("^"+email+"$"); 045 046 047 048 049 pairType[0]=EMAIL_NAME; 050 pairType[1]=EMAIL_NAME; 051 pairType[2]=NAME_EMAIL; 052 pairType[3]=NAME_EMAIL; 053 pairType[4]=NAME_EMAIL; 054 pairType[5]=NAME_EMAIL; 055 pairType[6]=EMAIL; 056 pairType[7]=EMAIL; 057 058 } 059 060 private EmailNamePair(String email,String name) { 061 this.name=name; 062 this.email=email; 063 } 064 065 private EmailNamePair(String strEmail) throws MailException { 066 strEmail=strEmail.trim(); 067 boolean hasMatch=false; 068 outer:for(int i=0;i<patterns.length;i++) { 069 Pattern p = patterns[i]; 070 Matcher m = p.matcher(strEmail); 071 072 if(m.matches()) { 073 switch(pairType[i]) { 074 case EMAIL: 075 email=clean(m.group(1)); 076 break; 077 case EMAIL_NAME: 078 email=clean(m.group(1)); 079 name=clean(m.group(2)); 080 break; 081 case NAME_EMAIL: 082 name=clean(m.group(1)); 083 email=clean(m.group(2)); 084 break; 085 } 086 hasMatch=true; 087 break outer; 088 } 089 } 090 if(!hasMatch) throw new MailException("Invalid E-Mail Address definition ("+strEmail+")"); 091 } 092 093 private static String clean(String str) { 094 if(str==null) return""; 095 096 str=str.trim(); 097 if((str.startsWith("'") && str.endsWith("'")) || (str.startsWith("\"") && str.endsWith("\""))) 098 return str.substring(1,str.length()-1).trim(); 099 return str; 100 } 101 102 103 public static InternetAddress toInternetAddress(Object emails) throws MailException, AddressException, UnsupportedEncodingException, PageException { 104 if(emails instanceof String){ 105 EmailNamePair pair = _factoryMail((String)emails); 106 if(!StringUtil.isEmpty(pair.getName()))return new InternetAddress(pair.getEmail(),pair.getName()); 107 return new InternetAddress(pair.getEmail()); 108 } 109 else { 110 InternetAddress[] addresses = toInternetAddresses(emails); 111 if(addresses!=null && addresses.length>0) return addresses[0]; 112 } 113 return null; 114 } 115 116 117 118 public static InternetAddress[] toInternetAddresses(Object emails) throws MailException, AddressException, UnsupportedEncodingException, PageException { 119 EmailNamePair[] pairs=null; 120 if(emails instanceof String){ 121 pairs = _factoryMailList((String)emails); 122 } 123 else if(Decision.isArray(emails)) { 124 pairs = _factory(Caster.toArray(emails)); 125 } 126 else if(Decision.isStruct(emails)) { 127 pairs = new EmailNamePair[]{_factory(Caster.toStruct(emails))}; 128 } 129 else 130 throw new MailException("e-mail defintions must be one of the following types [string,array,struct], not ["+emails.getClass().getName()+"]"); 131 132 133 InternetAddress[] addresses=new InternetAddress[pairs.length]; 134 EmailNamePair pair; 135 for(int i=0;i<pairs.length;i++) { 136 pair=pairs[i]; 137 if(!StringUtil.isEmpty(pair.getName()))addresses[i]=new InternetAddress(pair.getEmail(),pair.getName()); 138 else addresses[i]=new InternetAddress(pair.getEmail()); 139 } 140 return addresses; 141 } 142 143 144 private static EmailNamePair[] _factory(Array array) throws MailException, PageException { 145 Iterator it = array.valueIterator(); 146 Object el; 147 ArrayList<EmailNamePair> pairs=new ArrayList<EmailNamePair>(); 148 while(it.hasNext()){ 149 el=it.next(); 150 if(Decision.isStruct(el)) 151 pairs.add(_factory(Caster.toStruct(el))); 152 else 153 pairs.add(new EmailNamePair(Caster.toString(el))); 154 } 155 return pairs.toArray(new EmailNamePair[pairs.size()]); 156 } 157 158 private static EmailNamePair _factory(Struct sct) throws MailException { 159 String name=Caster.toString(sct.get("label",null),null); 160 if(name==null)name=Caster.toString(sct.get("name",null),null); 161 162 String email=Caster.toString(sct.get("email",null),null); 163 if(email==null)email=Caster.toString(sct.get("e-mail",null),null); 164 if(email==null)email=Caster.toString(sct.get("mail",null),null); 165 166 if(name==null) name=""; 167 if(StringUtil.isEmpty(email)) throw new MailException("missing e-mail defintion in struct"); 168 169 return new EmailNamePair(email,name); 170 } 171 172 /** 173 * parse a string with email name pairs and return it as array 174 * @param strEmails email name pairs a string 175 * @return parsed email n ame pairs 176 * @throws MailException 177 */ 178 private static EmailNamePair[] _factoryMailList(String strEmails) throws MailException { 179 if(StringUtil.isEmpty(strEmails,true)) return new EmailNamePair[0]; 180 Array raw = List.listWithQuotesToArray(strEmails,",;","\""); 181 182 Iterator<String> it = raw.valueIterator(); 183 ArrayList<EmailNamePair> pairs=new ArrayList<EmailNamePair>(); 184 String address; 185 while(it.hasNext()) { 186 address=it.next(); 187 if(StringUtil.isEmpty(address,true))continue; 188 pairs.add(new EmailNamePair(address)); 189 } 190 return pairs.toArray(new EmailNamePair[pairs.size()]); 191 } 192 193 194 private static EmailNamePair _factoryMail(String strEmail) throws MailException { 195 if(StringUtil.isEmpty(strEmail,true)) return null; 196 return new EmailNamePair(strEmail); 197 } 198 199 200 201 202 203 204 /** 205 * @return return if in the email name pair also a name is defined 206 */ 207 public boolean hasName() { 208 return name.length()>0; 209 } 210 /** 211 * @return returns the name 212 */ 213 public String getName() { 214 return name; 215 } 216 /** 217 * @return returns the email 218 */ 219 public String getEmail() { 220 return email; 221 } 222 223 /** 224 * @see java.lang.Object#toString() 225 */ 226 public String toString() { 227 if(name.length()==0) return email; 228 return email+"("+name+")"; 229 } 230 231 }