KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > mail > internet > InternetAddress


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)InternetAddress.java 1.47 05/08/29
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package javax.mail.internet;
29
30 import java.io.UnsupportedEncodingException JavaDoc;
31 import java.net.InetAddress JavaDoc;
32 import java.net.UnknownHostException JavaDoc;
33 import java.util.Vector JavaDoc;
34 import java.util.StringTokenizer JavaDoc;
35 import javax.mail.*;
36
37 /**
38  * This class represents an Internet email address using the syntax
39  * of <a HREF="http://www.ietf.org/rfc/rfc822.txt">RFC822</a>.
40  * Typical address syntax is of the form "user@host.domain" or
41  * "Personal Name <user@host.domain>".
42  *
43  * @author Bill Shannon
44  * @author John Mani
45  */

46
47 public class InternetAddress extends Address JavaDoc implements Cloneable JavaDoc {
48
49     protected String JavaDoc address; // email address
50

51     /**
52      * The personal name.
53      */

54     protected String JavaDoc personal;
55
56     /**
57      * The RFC 2047 encoded version of the personal name. <p>
58      *
59      * This field and the <code>personal</code> field track each
60      * other, so if a subclass sets one of these fields directly, it
61      * should set the other to <code>null</code>, so that it is
62      * suitably recomputed.
63      */

64     protected String JavaDoc encodedPersonal;
65
66     private static final long serialVersionUID = -7507595530758302903L;
67
68     /**
69      * Default constructor.
70      */

71     public InternetAddress() { }
72
73     /**
74      * Constructor. <p>
75      *
76      * Parse the given string and create an InternetAddress.
77      * See the <code>parse</code> method for details of the parsing.
78      * The address is parsed using "strict" parsing.
79      * This constructor does <b>not</b> perform the additional
80      * syntax checks that the
81      * <code>InternetAddress(String address, boolean strict)</code>
82      * constructor does when <code>strict</code> is <code>true</code>.
83      * This constructor is equivalent to
84      * <code>InternetAddress(address, false)</code>.
85      *
86      * @param address the address in RFC822 format
87      * @exception AddressException if the parse failed
88      */

89     public InternetAddress(String JavaDoc address) throws AddressException JavaDoc {
90     // use our address parsing utility routine to parse the string
91
InternetAddress JavaDoc a[] = parse(address, true);
92     // if we got back anything other than a single address, it's an error
93
if (a.length != 1)
94         throw new AddressException JavaDoc("Illegal address", address);
95
96     /*
97      * Now copy the contents of the single address we parsed
98      * into the current object, which will be returned from the
99      * constructor.
100      * XXX - this sure is a round-about way of getting this done.
101      */

102     this.address = a[0].address;
103     this.personal = a[0].personal;
104     this.encodedPersonal = a[0].encodedPersonal;
105     }
106
107     /**
108      * Parse the given string and create an InternetAddress.
109      * If <code>strict</code> is false, the detailed syntax of the
110      * address isn't checked.
111      *
112      * @param address the address in RFC822 format
113      * @param strict enforce RFC822 syntax
114      * @exception AddressException if the parse failed
115      * @since JavaMail 1.3
116      */

117     public InternetAddress(String JavaDoc address, boolean strict)
118                         throws AddressException JavaDoc {
119     this(address);
120     if (strict)
121         checkAddress(this.address, true, true);
122     }
123
124     /**
125      * Construct an InternetAddress given the address and personal name.
126      * The address is assumed to be a syntactically valid RFC822 address.
127      *
128      * @param address the address in RFC822 format
129      * @param personal the personal name
130      */

131     public InternetAddress(String JavaDoc address, String JavaDoc personal)
132                 throws UnsupportedEncodingException JavaDoc {
133     this(address, personal, null);
134     }
135
136     /**
137      * Construct an InternetAddress given the address and personal name.
138      * The address is assumed to be a syntactically valid RFC822 address.
139      *
140      * @param address the address in RFC822 format
141      * @param personal the personal name
142      * @param charset the MIME charset for the name
143      */

144     public InternetAddress(String JavaDoc address, String JavaDoc personal, String JavaDoc charset)
145                 throws UnsupportedEncodingException JavaDoc {
146     this.address = address;
147     setPersonal(personal, charset);
148     }
149
150     /**
151      * Return a copy of this InternetAddress object.
152      * @since JavaMail 1.2
153      */

154     public Object JavaDoc clone() {
155     InternetAddress JavaDoc a = null;
156     try {
157         a = (InternetAddress JavaDoc)super.clone();
158     } catch (CloneNotSupportedException JavaDoc e) {} // Won't happen
159
return a;
160     }
161
162     /**
163      * Return the type of this address. The type of an InternetAddress
164      * is "rfc822".
165      */

166     public String JavaDoc getType() {
167     return "rfc822";
168     }
169
170     /**
171      * Set the email address.
172      *
173      * @param address email address
174      */

175     public void setAddress(String JavaDoc address) {
176     this.address = address;
177     }
178
179     /**
180      * Set the personal name. If the name contains non US-ASCII
181      * characters, then the name will be encoded using the specified
182      * charset as per RFC 2047. If the name contains only US-ASCII
183      * characters, no encoding is done and the name is used as is. <p>
184      *
185      * @param name personal name
186      * @param charset MIME charset to be used to encode the name as
187      * per RFC 2047
188      * @see #setPersonal(String)
189      * @exception UnsupportedEncodingException if the charset encoding
190      * fails.
191      */

192     public void setPersonal(String JavaDoc name, String JavaDoc charset)
193                 throws UnsupportedEncodingException JavaDoc {
194     personal = name;
195     if (name != null)
196         encodedPersonal = MimeUtility.encodeWord(name, charset, null);
197     else
198         encodedPersonal = null;
199     }
200
201     /**
202      * Set the personal name. If the name contains non US-ASCII
203      * characters, then the name will be encoded using the platform's
204      * default charset. If the name contains only US-ASCII characters,
205      * no encoding is done and the name is used as is. <p>
206      *
207      * @param name personal name
208      * @see #setPersonal(String name, String charset)
209      * @exception UnsupportedEncodingException if the charset encoding
210      * fails.
211      */

212     public void setPersonal(String JavaDoc name)
213         throws UnsupportedEncodingException JavaDoc {
214     personal = name;
215     if (name != null)
216         encodedPersonal = MimeUtility.encodeWord(name);
217     else
218         encodedPersonal = null;
219     }
220
221     /**
222      * Get the email address.
223      * @return email address
224      */

225     public String JavaDoc getAddress() {
226     return address;
227     }
228
229     /**
230      * Get the personal name. If the name is encoded as per RFC 2047,
231      * it is decoded and converted into Unicode. If the decoding or
232      * conversion fails, the raw data is returned as is.
233      *
234      * @return personal name
235      */

236     public String JavaDoc getPersonal() {
237     if (personal != null)
238         return personal;
239     
240     if (encodedPersonal != null) {
241         try {
242         personal = MimeUtility.decodeText(encodedPersonal);
243         return personal;
244         } catch (Exception JavaDoc ex) {
245         // 1. ParseException: either its an unencoded string or
246
// it can't be parsed
247
// 2. UnsupportedEncodingException: can't decode it.
248
return encodedPersonal;
249         }
250     }
251     // No personal or encodedPersonal, return null
252
return null;
253     }
254
255     /**
256      * Convert this address into a RFC 822 / RFC 2047 encoded address.
257      * The resulting string contains only US-ASCII characters, and
258      * hence is mail-safe.
259      *
260      * @return possibly encoded address string
261      */

262     public String JavaDoc toString() {
263     if (encodedPersonal == null && personal != null)
264         try {
265         encodedPersonal = MimeUtility.encodeWord(personal);
266         } catch (UnsupportedEncodingException JavaDoc ex) { }
267     
268     if (encodedPersonal != null)
269         return quotePhrase(encodedPersonal) + " <" + address + ">";
270     else if (isGroup() || isSimple())
271         return address;
272     else
273         return "<" + address + ">";
274     }
275
276     /**
277      * Returns a properly formatted address (RFC 822 syntax) of
278      * Unicode characters.
279      *
280      * @return Unicode address string
281      * @since JavaMail 1.2
282      */

283     public String JavaDoc toUnicodeString() {
284     String JavaDoc p = getPersonal();
285         if (p != null)
286             return quotePhrase(p) + " <" + address + ">";
287         else if (isGroup() || isSimple())
288             return address;
289         else
290             return "<" + address + ">";
291     }
292
293     /*
294      * quotePhrase() quotes the words within a RFC822 phrase.
295      *
296      * This is tricky, since a phrase is defined as 1 or more
297      * RFC822 words, separated by LWSP. Now, a word that contains
298      * LWSP is supposed to be quoted, and this is exactly what the
299      * MimeUtility.quote() method does. However, when dealing with
300      * a phrase, any LWSP encountered can be construed to be the
301      * separator between words, and not part of the words themselves.
302      * To deal with this funkiness, we have the below variant of
303      * MimeUtility.quote(), which essentially ignores LWSP when
304      * deciding whether to quote a word.
305      *
306      * It aint pretty, but it gets the job done :)
307      */

308
309     private static final String JavaDoc rfc822phrase =
310     HeaderTokenizer.RFC822.replace(' ', '\0').replace('\t', '\0');
311
312     private static String JavaDoc quotePhrase(String JavaDoc phrase) {
313         int len = phrase.length();
314         boolean needQuoting = false;
315
316         for (int i = 0; i < len; i++) {
317             char c = phrase.charAt(i);
318             if (c == '"' || c == '\\') {
319                 // need to escape them and then quote the whole string
320
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(len + 3);
321                 sb.append('"');
322                 for (int j = 0; j < len; j++) {
323                     char cc = phrase.charAt(j);
324                     if (cc == '"' || cc == '\\')
325                         // Escape the character
326
sb.append('\\');
327                     sb.append(cc);
328                 }
329                 sb.append('"');
330                 return sb.toString();
331             } else if ((c < 040 && c != '\r' && c != '\n' && c != '\t') ||
332             c >= 0177 || rfc822phrase.indexOf(c) >= 0)
333                // These characters cause the string to be quoted
334
needQuoting = true;
335         }
336
337         if (needQuoting) {
338             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(len + 2);
339             sb.append('"').append(phrase).append('"');
340             return sb.toString();
341         } else
342             return phrase;
343     }
344
345     private static String JavaDoc unquote(String JavaDoc s) {
346     if (s.startsWith("\"") && s.endsWith("\"")) {
347         s = s.substring(1, s.length() - 1);
348         // check for any escaped characters
349
if (s.indexOf('\\') >= 0) {
350         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(s.length()); // approx
351
for (int i = 0; i < s.length(); i++) {
352             char c = s.charAt(i);
353             if (c == '\\' && i < s.length() - 1)
354             c = s.charAt(++i);
355             sb.append(c);
356         }
357         s = sb.toString();
358         }
359     }
360     return s;
361     }
362
363     /**
364      * The equality operator.
365      */

366     public boolean equals(Object JavaDoc a) {
367     if (!(a instanceof InternetAddress JavaDoc))
368         return false;
369
370     String JavaDoc s = ((InternetAddress JavaDoc)a).getAddress();
371     if (s == address)
372         return true;
373     if (address != null && address.equalsIgnoreCase(s))
374         return true;
375
376     return false;
377     }
378
379     /**
380      * Compute a hash code for the address.
381      */

382     public int hashCode() {
383     if (address == null)
384         return 0;
385     else
386         return address.toLowerCase().hashCode();
387     }
388
389     /**
390      * Convert the given array of InternetAddress objects into
391      * a comma separated sequence of address strings. The
392      * resulting string contains only US-ASCII characters, and
393      * hence is mail-safe. <p>
394      *
395      * @param addresses array of InternetAddress objects
396      * @exception ClassCastException, if any address object in the
397      * given array is not an InternetAddress object. Note
398      * that this is a RuntimeException.
399      * @return comma separated string of addresses
400      */

401     public static String JavaDoc toString(Address JavaDoc[] addresses) {
402     return toString(addresses, 0);
403     }
404
405     /**
406      * Convert the given array of InternetAddress objects into
407      * a comma separated sequence of address strings. The
408      * resulting string contains only US-ASCII characters, and
409      * hence is mail-safe. <p>
410      *
411      * The 'used' parameter specifies the number of character positions
412      * already taken up in the field into which the resulting address
413      * sequence string is to be inserted. It is used to determine the
414      * line-break positions in the resulting address sequence string.
415      *
416      * @param addresses array of InternetAddress objects
417      * @param used number of character positions already used, in
418      * the field into which the address string is to
419      * be inserted.
420      * @exception ClassCastException, if any address object in the
421      * given array is not an InternetAddress object. Note
422      * that this is a RuntimeException.
423      * @return comma separated string of addresses
424      */

425     public static String JavaDoc toString(Address JavaDoc[] addresses, int used) {
426     if (addresses == null || addresses.length == 0)
427         return null;
428
429     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
430
431     for (int i = 0; i < addresses.length; i++) {
432         if (i != 0) { // need to append comma
433
sb.append(", ");
434         used += 2;
435         }
436
437         String JavaDoc s = addresses[i].toString();
438         int len = lengthOfFirstSegment(s); // length till CRLF
439
if (used + len > 76) { // overflows ...
440
sb.append("\r\n\t"); // .. start new continuation line
441
used = 8; // account for the starting <tab> char
442
}
443         sb.append(s);
444         used = lengthOfLastSegment(s, used);
445     }
446
447     return sb.toString();
448     }
449
450     /* Return the length of the first segment within this string.
451      * If no segments exist, the length of the whole line is returned.
452      */

453     private static int lengthOfFirstSegment(String JavaDoc s) {
454     int pos;
455     if ((pos = s.indexOf("\r\n")) != -1)
456         return pos;
457     else
458         return s.length();
459     }
460
461     /*
462      * Return the length of the last segment within this string.
463      * If no segments exist, the length of the whole line plus
464      * <code>used</code> is returned.
465      */

466     private static int lengthOfLastSegment(String JavaDoc s, int used) {
467     int pos;
468     if ((pos = s.lastIndexOf("\r\n")) != -1)
469         return s.length() - pos - 2;
470     else
471         return s.length() + used;
472     }
473
474     /**
475      * Return an InternetAddress object representing the current user.
476      * The entire email address may be specified in the "mail.from"
477      * property. If not set, the "mail.user" and "mail.host" properties
478      * are tried. If those are not set, the "user.name" property and
479      * <code>InetAddress.getLocalHost</code> method are tried.
480      * Security exceptions that may occur while accessing this information
481      * are ignored. If it is not possible to determine an email address,
482      * null is returned.
483      *
484      * @param session Session object used for property lookup
485      * @return current user's email address
486      */

487     public static InternetAddress JavaDoc getLocalAddress(Session session) {
488     String JavaDoc user=null, host=null, address=null;
489     try {
490         if (session == null) {
491         user = System.getProperty("user.name");
492         host = InetAddress.getLocalHost().getHostName();
493         } else {
494         address = session.getProperty("mail.from");
495         if (address == null) {
496             user = session.getProperty("mail.user");
497             if (user == null || user.length() == 0)
498             user = session.getProperty("user.name");
499             if (user == null || user.length() == 0)
500             user = System.getProperty("user.name");
501             host = session.getProperty("mail.host");
502             if (host == null || host.length() == 0) {
503             InetAddress JavaDoc me = InetAddress.getLocalHost();
504             if (me != null)
505                 host = me.getHostName();
506             }
507         }
508         }
509
510         if (address == null && user != null && user.length() != 0 &&
511             host != null && host.length() != 0)
512         address = user + "@" + host;
513
514         if (address != null)
515         return new InternetAddress JavaDoc(address);
516     } catch (SecurityException JavaDoc sex) { // ignore it
517
} catch (AddressException JavaDoc ex) { // ignore it
518
} catch (UnknownHostException JavaDoc ex) { } // ignore it
519
return null;
520     }
521
522     /**
523      * Parse the given comma separated sequence of addresses into
524      * InternetAddress objects. Addresses must follow RFC822 syntax.
525      *
526      * @param addresslist comma separated address strings
527      * @return array of InternetAddress objects
528      * @exception AddressException if the parse failed
529      */

530     public static InternetAddress JavaDoc[] parse(String JavaDoc addresslist)
531                 throws AddressException JavaDoc {
532     return parse(addresslist, true);
533     }
534
535     /**
536      * Parse the given sequence of addresses into InternetAddress
537      * objects. If <code>strict</code> is false, simple email addresses
538      * separated by spaces are also allowed. If <code>strict</code> is
539      * true, many (but not all) of the RFC822 syntax rules are enforced.
540      * In particular, even if <code>strict</code> is true, addresses
541      * composed of simple names (with no "@domain" part) are allowed.
542      * Such "illegal" addresses are not uncommon in real messages. <p>
543      *
544      * Non-strict parsing is typically used when parsing a list of
545      * mail addresses entered by a human. Strict parsing is typically
546      * used when parsing address headers in mail messages.
547      *
548      * @param addresslist comma separated address strings
549      * @param strict enforce RFC822 syntax
550      * @return array of InternetAddress objects
551      * @exception AddressException if the parse failed
552      */

553     public static InternetAddress JavaDoc[] parse(String JavaDoc addresslist, boolean strict)
554                         throws AddressException JavaDoc {
555     return parse(addresslist, strict, false);
556     }
557
558     /**
559      * Parse the given sequence of addresses into InternetAddress
560      * objects. If <code>strict</code> is false, the full syntax rules for
561      * individual addresses are not enforced. If <code>strict</code> is
562      * true, many (but not all) of the RFC822 syntax rules are enforced. <p>
563      *
564      * To better support the range of "invalid" addresses seen in real
565      * messages, this method enforces fewer syntax rules than the
566      * <code>parse</code> method when the strict flag is false
567      * and enforces more rules when the strict flag is true. If the
568      * strict flag is false and the parse is successful in separating out an
569      * email address or addresses, the syntax of the addresses themselves
570      * is not checked.
571      *
572      * @param addresslist comma separated address strings
573      * @param strict enforce RFC822 syntax
574      * @return array of InternetAddress objects
575      * @exception AddressException if the parse failed
576      * @since JavaMail 1.3
577      */

578     public static InternetAddress JavaDoc[] parseHeader(String JavaDoc addresslist,
579                 boolean strict) throws AddressException JavaDoc {
580     return parse(addresslist, strict, true);
581     }
582
583     /*
584      * RFC822 Address parser.
585      *
586      * XXX - This is complex enough that it ought to be a real parser,
587      * not this ad-hoc mess, and because of that, this is not perfect.
588      *
589      * XXX - Deal with encoded Headers too.
590      */

591     private static InternetAddress JavaDoc[] parse(String JavaDoc s, boolean strict,
592                     boolean parseHdr) throws AddressException JavaDoc {
593     int start, end, index, nesting;
594     int start_personal = -1, end_personal = -1;
595     int length = s.length();
596     boolean in_group = false; // we're processing a group term
597
boolean route_addr = false; // address came from route-addr term
598
boolean rfc822 = false; // looks like an RFC822 address
599
char c;
600     Vector JavaDoc v = new Vector JavaDoc();
601     InternetAddress JavaDoc ma;
602
603     for (start = end = -1, index = 0; index < length; index++) {
604             c = s.charAt(index);
605
606         switch (c) {
607         case '(': // We are parsing a Comment. Ignore everything inside.
608
// XXX - comment fields should be parsed as whitespace,
609
// more than one allowed per address
610
rfc822 = true;
611         if (start >= 0 && end == -1)
612             end = index;
613         if (start_personal == -1)
614             start_personal = index + 1;
615         for (index++, nesting = 1; index < length && nesting > 0;
616           index++) {
617             c = s.charAt(index);
618             switch (c) {
619             case '\\':
620             index++; // skip both '\' and the escaped char
621
break;
622             case '(':
623             nesting++;
624             break;
625             case ')':
626             nesting--;
627             break;
628             default:
629             break;
630             }
631         }
632         if (nesting > 0)
633             throw new AddressException JavaDoc("Missing ')'", s, index);
634         index--; // point to closing paren
635
if (end_personal == -1)
636             end_personal = index;
637         break;
638
639         case ')':
640         throw new AddressException JavaDoc("Missing '('", s, index);
641
642         case '<':
643         rfc822 = true;
644         if (route_addr)
645             throw new AddressException JavaDoc("Extra route-addr", s, index);
646         if (!in_group) {
647             start_personal = start;
648             if (start_personal >= 0)
649             end_personal = index;
650             start = index + 1;
651         }
652
653         boolean inquote = false;
654           outf:
655         for (index++; index < length; index++) {
656             c = s.charAt(index);
657             switch (c) {
658             case '\\': // XXX - is this needed?
659
index++; // skip both '\' and the escaped char
660
break;
661             case '"':
662             inquote = !inquote;
663             break;
664             case '>':
665             if (inquote)
666                 continue;
667             break outf; // out of for loop
668
default:
669             break;
670             }
671         }
672         if (index >= length) {
673             if (inquote)
674             throw new AddressException JavaDoc("Missing '\"'", s, index);
675             else
676             throw new AddressException JavaDoc("Missing '>'", s, index);
677         }
678         route_addr = true;
679         end = index;
680         break;
681         case '>':
682         throw new AddressException JavaDoc("Missing '<'", s, index);
683
684         case '"': // parse quoted string
685
rfc822 = true;
686         if (start == -1)
687             start = index;
688           outq:
689         for (index++; index < length; index++) {
690             c = s.charAt(index);
691             switch (c) {
692             case '\\':
693             index++; // skip both '\' and the escaped char
694
break;
695             case '"':
696             break outq; // out of for loop
697
default:
698             break;
699             }
700         }
701         if (index >= length)
702             throw new AddressException JavaDoc("Missing '\"'", s, index);
703         break;
704
705         case '[': // a domain-literal, probably
706
rfc822 = true;
707           outb:
708         for (index++; index < length; index++) {
709             c = s.charAt(index);
710             switch (c) {
711             case '\\':
712             index++; // skip both '\' and the escaped char
713
break;
714             case ']':
715             break outb; // out of for loop
716
default:
717             break;
718             }
719         }
720         if (index >= length)
721             throw new AddressException JavaDoc("Missing ']'", s, index);
722         break;
723
724         case ',': // end of an address, probably
725
if (start == -1) {
726             route_addr = false;
727             rfc822 = false;
728             start = end = -1;
729             break; // nope, nothing there
730
}
731         if (in_group) {
732             route_addr = false;
733             break;
734         }
735         // got a token, add this to our InternetAddress vector
736
if (end == -1)
737             end = index;
738         String JavaDoc addr = s.substring(start, end).trim();
739         if (rfc822 || strict || parseHdr) {
740             if (strict || !parseHdr)
741             checkAddress(addr, route_addr, false);
742             ma = new InternetAddress JavaDoc();
743             ma.setAddress(addr);
744             if (start_personal >= 0) {
745             ma.encodedPersonal = unquote(
746                 s.substring(start_personal, end_personal).trim());
747             start_personal = end_personal = -1;
748             }
749             v.addElement(ma);
750         } else {
751             // maybe we passed over more than one space-separated addr
752
StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(addr);
753             while (st.hasMoreTokens()) {
754             String JavaDoc a = st.nextToken();
755             checkAddress(a, false, false);
756             ma = new InternetAddress JavaDoc();
757             ma.setAddress(a);
758             v.addElement(ma);
759             }
760         }
761
762         route_addr = false;
763         rfc822 = false;
764         start = end = -1;
765         break;
766
767         case ':':
768         rfc822 = true;
769         if (in_group)
770             throw new AddressException JavaDoc("Nested group", s, index);
771         in_group = true;
772         if (start == -1)
773             start = index;
774         break;
775
776         case ';':
777         if (start == -1)
778             start = index;
779         if (!in_group)
780             throw new AddressException JavaDoc(
781                 "Illegal semicolon, not in group", s, index);
782         in_group = false;
783         if (start == -1)
784             start = index;
785         ma = new InternetAddress JavaDoc();
786         end = index + 1;
787         ma.setAddress(s.substring(start, end).trim());
788         v.addElement(ma);
789
790         route_addr = false;
791         start = end = -1;
792         break;
793
794         // Ignore whitespace
795
case ' ':
796         case '\t':
797         case '\r':
798         case '\n':
799         break;
800
801         default:
802         if (start == -1)
803             start = index;
804         break;
805          }
806     }
807
808     if (start >= 0) {
809         /*
810          * The last token, add this to our InternetAddress vector.
811          * Note that this block of code should be identical to the
812          * block above for "case ','".
813          */

814         if (end == -1)
815         end = index;
816         String JavaDoc addr = s.substring(start, end).trim();
817         if (rfc822 || strict || parseHdr) {
818         if (strict || !parseHdr)
819             checkAddress(addr, route_addr, false);
820         ma = new InternetAddress JavaDoc();
821         ma.setAddress(addr);
822         if (start_personal >= 0) {
823             ma.encodedPersonal = unquote(
824                 s.substring(start_personal, end_personal).trim());
825         }
826         v.addElement(ma);
827         } else {
828         // maybe we passed over more than one space-separated addr
829
StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(addr);
830         while (st.hasMoreTokens()) {
831             String JavaDoc a = st.nextToken();
832             checkAddress(a, false, false);
833             ma = new InternetAddress JavaDoc();
834             ma.setAddress(a);
835             v.addElement(ma);
836         }
837         }
838     }
839
840     InternetAddress JavaDoc[] a = new InternetAddress JavaDoc[v.size()];
841     v.copyInto(a);
842     return a;
843     }
844
845     /**
846      * Validate that this address conforms to the syntax rules of
847      * RFC 822. The current implementation checks many, but not
848      * all, syntax rules. Note that even though the syntax of
849      * the address may be correct, there's no guarantee that a
850      * mailbox of that name exists.
851      *
852      * @exception AddressException if the address isn't valid.
853      * @since JavaMail 1.3
854      */

855     public void validate() throws AddressException JavaDoc {
856     checkAddress(getAddress(), true, true);
857     }
858
859     private static final String JavaDoc specialsNoDotNoAt = "()<>,;:\\\"[]";
860     private static final String JavaDoc specialsNoDot = specialsNoDotNoAt + "@";
861
862     /**
863      * Check that the address is a valid "mailbox" per RFC822.
864      * (We also allow simple names.)
865      *
866      * XXX - much more to check
867      * XXX - doesn't handle domain-literals properly (but no one uses them)
868      */

869     private static void checkAddress(String JavaDoc addr,
870                 boolean routeAddr, boolean validate)
871                 throws AddressException JavaDoc {
872     int i, start = 0;
873     if (addr.indexOf('"') >= 0)
874         return; // quote in address, too hard to check
875
if (routeAddr) {
876         /*
877          * Check for a legal "route-addr":
878          * [@domain[,@domain ...]:]local@domain
879          */

880         for (start = 0; (i = indexOfAny(addr, ",:", start)) >= 0;
881             start = i+1) {
882         if (addr.charAt(start) != '@')
883             throw new AddressException JavaDoc("Illegal route-addr", addr);
884         if (addr.charAt(i) == ':') {
885             // end of route-addr
886
start = i + 1;
887             break;
888         }
889         }
890     }
891     /*
892      * The rest should be "local@domain", but we allow simply "local"
893      * unless called from validate.
894      */

895     String JavaDoc local;
896     String JavaDoc domain;
897     if ((i = addr.indexOf('@', start)) >= 0) {
898         if (i == start)
899         throw new AddressException JavaDoc("Missing local name", addr);
900         if (i == addr.length() - 1)
901         throw new AddressException JavaDoc("Missing domain", addr);
902         local = addr.substring(start, i);
903         domain = addr.substring(i + 1);
904     } else {
905         /*
906          * Note that the MimeMessage class doesn't remember addresses
907          * as separate objects; it writes them out as headers and then
908          * parses the headers when the addresses are requested.
909          * In order to support the case where a "simple" address is used,
910          * but the address also has a personal name and thus looks like
911          * it should be a valid RFC822 address when parsed, we only check
912          * this if we're explicitly called from the validate method.
913          */

914         if (validate)
915         throw new AddressException JavaDoc("Missing final '@domain'", addr);
916
917         /*
918          * No '@' so it's not *really* an RFC822 address, but still
919          * we allow some simple forms.
920          */

921         local = addr;
922         domain = null;
923     }
924     // there better not be any whitespace in it
925
if (indexOfAny(addr, " \t\n\r") >= 0)
926         throw new AddressException JavaDoc("Illegal whitespace in address", addr);
927     // local-part must follow RFC822, no specials except '.'
928
if (indexOfAny(local, specialsNoDot) >= 0)
929         throw new AddressException JavaDoc("Illegal character in local name", addr);
930     // check for illegal chars in the domain, but ignore domain literals
931
if (domain != null && domain.indexOf('[') < 0) {
932         if (indexOfAny(domain, specialsNoDot) >= 0)
933         throw new AddressException JavaDoc("Illegal character in domain", addr);
934     }
935     }
936
937     /**
938      * Is this a "simple" address? Simple addresses don't contain quotes
939      * or any RFC822 special characters other than '@' and '.'.
940      */

941     private boolean isSimple() {
942     return address == null || indexOfAny(address, specialsNoDotNoAt) < 0;
943     }
944
945     /**
946      * Indicates whether this address is an RFC 822 group address.
947      * Note that a group address is different than the mailing
948      * list addresses supported by most mail servers. Group addresses
949      * are rarely used; see RFC 822 for details.
950      *
951      * @return true if this address represents a group
952      * @since JavaMail 1.3
953      */

954     public boolean isGroup() {
955     // quick and dirty check
956
return address != null &&
957         address.endsWith(";") && address.indexOf(':') > 0;
958     }
959
960     /**
961      * Return the members of a group address. A group may have zero,
962      * one, or more members. If this address is not a group, null
963      * is returned. The <code>strict</code> parameter controls whether
964      * the group list is parsed using strict RFC 822 rules or not.
965      * The parsing is done using the <code>parseHeader</code> method.
966      *
967      * @return array of InternetAddress objects, or null
968      * @exception AddressException if the group list can't be parsed
969      * @since JavaMail 1.3
970      */

971     public InternetAddress JavaDoc[] getGroup(boolean strict) throws AddressException JavaDoc {
972     Vector JavaDoc groups = null;
973     String JavaDoc addr = getAddress();
974     // groups are of the form "name:addr,addr,...;"
975
if (!addr.endsWith(";"))
976         return null;
977     int ix = addr.indexOf(':');
978     if (ix < 0)
979         return null;
980     // extract the list
981
String JavaDoc list = addr.substring(ix + 1, addr.length() - 1);
982     // parse it and return the individual addresses
983
return InternetAddress.parseHeader(list, strict);
984     }
985
986     /**
987      * Return the first index of any of the characters in "any" in "s",
988      * or -1 if none are found.
989      *
990      * This should be a method on String.
991      */

992     private static int indexOfAny(String JavaDoc s, String JavaDoc any) {
993     return indexOfAny(s, any, 0);
994     }
995
996     private static int indexOfAny(String JavaDoc s, String JavaDoc any, int start) {
997     try {
998         int len = s.length();
999         for (int i = start; i < len; i++) {
1000        if (any.indexOf(s.charAt(i)) >= 0)
1001            return i;
1002        }
1003        return -1;
1004    } catch (StringIndexOutOfBoundsException JavaDoc e) {
1005        return -1;
1006    }
1007    }
1008
1009    /*
1010    public static void main(String argv[]) throws Exception {
1011    for (int i = 0; i < argv.length; i++) {
1012        InternetAddress[] a = InternetAddress.parse(argv[i]);
1013        for (int j = 0; j < a.length; j++) {
1014        System.out.println("arg " + i + " address " + j + ": " + a[j]);
1015        System.out.println("\tAddress: " + a[j].getAddress() +
1016                    "\tPersonal: " + a[j].getPersonal());
1017        }
1018        if (a.length > 1) {
1019        System.out.println("address 0 hash code: " + a[0].hashCode());
1020        System.out.println("address 1 hash code: " + a[1].hashCode());
1021        if (a[0].hashCode() == a[1].hashCode())
1022            System.out.println("success, hashcodes equal");
1023        else
1024            System.out.println("fail, hashcodes not equal");
1025        if (a[0].equals(a[1]))
1026            System.out.println("success, addresses equal");
1027        else
1028            System.out.println("fail, addresses not equal");
1029        if (a[1].equals(a[0]))
1030            System.out.println("success, addresses equal");
1031        else
1032            System.out.println("fail, addresses not equal");
1033        }
1034    }
1035    }
1036    */

1037}
1038
Popular Tags