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