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    }