Source Code Cross Referenced for MailAddress.java in  » Net » james-2.3.1 » org » apache » mailet » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » james 2.3.1 » org.apache.mailet 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /****************************************************************
002:         * Licensed to the Apache Software Foundation (ASF) under one   *
003:         * or more contributor license agreements.  See the NOTICE file *
004:         * distributed with this work for additional information        *
005:         * regarding copyright ownership.  The ASF licenses this file   *
006:         * to you under the Apache License, Version 2.0 (the            *
007:         * "License"); you may not use this file except in compliance   *
008:         * with the License.  You may obtain a copy of the License at   *
009:         *                                                              *
010:         *   http://www.apache.org/licenses/LICENSE-2.0                 *
011:         *                                                              *
012:         * Unless required by applicable law or agreed to in writing,   *
013:         * software distributed under the License is distributed on an  *
014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015:         * KIND, either express or implied.  See the License for the    *
016:         * specific language governing permissions and limitations      *
017:         * under the License.                                           *
018:         ****************************************************************/package org.apache.mailet;
019:
020:        import java.util.Locale;
021:        import javax.mail.internet.InternetAddress;
022:        import javax.mail.internet.ParseException;
023:
024:        /**
025:         * A representation of an email address.
026:         * <p>This class encapsulates functionalities to access to different
027:         * parts of an email address without dealing with its parsing.</p>
028:         *
029:         * <p>A MailAddress is an address specified in the MAIL FROM and
030:         * RCPT TO commands in SMTP sessions.  These are either passed by
031:         * an external server to the mailet-compliant SMTP server, or they
032:         * are created programmatically by the mailet-compliant server to
033:         * send to another (external) SMTP server.  Mailets and matchers
034:         * use the MailAddress for the purpose of evaluating the sender
035:         * and recipient(s) of a message.</p>
036:         *
037:         * <p>MailAddress parses an email address as defined in RFC 821
038:         * (SMTP) p. 30 and 31 where addresses are defined in BNF convention.
039:         * As the mailet API does not support the aged "SMTP-relayed mail"
040:         * addressing protocol, this leaves all addresses to be a <mailbox>,
041:         * as per the spec.  The MailAddress's "user" is the <local-part> of
042:         * the <mailbox> and "host" is the <domain> of the mailbox.</p>
043:         *
044:         * <p>This class is a good way to validate email addresses as there are
045:         * some valid addresses which would fail with a simpler approach
046:         * to parsing address.  It also removes parsing burden from
047:         * mailets and matchers that might not realize the flexibility of an
048:         * SMTP address.  For instance, "serge@home"@lokitech.com is a valid
049:         * SMTP address (the quoted text serge@home is the user and
050:         * lokitech.com is the host).  This means all current parsing to date
051:         * is incorrect as we just find the first @ and use that to separate
052:         * user from host.</p>
053:         *
054:         * <p>This parses an address as per the BNF specification for <mailbox>
055:         * from RFC 821 on page 30 and 31, section 4.1.2. COMMAND SYNTAX.
056:         * http://www.freesoft.org/CIE/RFC/821/15.htm</p>
057:         *
058:         * @version 1.0
059:         */
060:        public class MailAddress implements  java.io.Serializable {
061:            //We hardcode the serialVersionUID so that from James 1.2 on,
062:            //  MailAddress will be deserializable (so your mail doesn't get lost)
063:            public static final long serialVersionUID = 2779163542539434916L;
064:
065:            private final static char[] SPECIAL = { '<', '>', '(', ')', '[',
066:                    ']', '\\', '.', ',', ';', ':', '@', '\"' };
067:
068:            private String user = null;
069:            private String host = null;
070:            //Used for parsing
071:            private int pos = 0;
072:
073:            /**
074:             * strip source routing, according to RFC-2821 it is an allowed approach to handle mails
075:             * contaning RFC-821 source-route information
076:             */
077:            private void stripSourceRoute(String address) throws ParseException {
078:                if (pos < address.length()) {
079:                    if (address.charAt(pos) == '@') {
080:                        int i = address.indexOf(':');
081:                        if (i != -1) {
082:                            pos = i + 1;
083:                        }
084:                    }
085:                }
086:            }
087:
088:            /**
089:             * <p>Construct a MailAddress parsing the provided <code>String</code> object.</p>
090:             *
091:             * <p>The <code>personal</code> variable is left empty.</p>
092:             *
093:             * @param   address the email address compliant to the RFC822 format
094:             * @throws  ParseException    if the parse failed
095:             */
096:            public MailAddress(String address) throws ParseException {
097:                address = address.trim();
098:
099:                // Test if mail address has source routing information (RFC-821) and get rid of it!!
100:                //must be called first!! (or at least prior to updating pos)
101:                stripSourceRoute(address);
102:
103:                StringBuffer userSB = new StringBuffer();
104:                StringBuffer hostSB = new StringBuffer();
105:                //Begin parsing
106:                //<mailbox> ::= <local-part> "@" <domain>
107:
108:                try {
109:                    //parse local-part
110:                    //<local-part> ::= <dot-string> | <quoted-string>
111:                    if (address.charAt(pos) == '\"') {
112:                        userSB.append(parseQuotedLocalPart(address));
113:                        if (userSB.toString().length() == 2) {
114:                            throw new ParseException(
115:                                    "No quoted local-part (user account) found at position "
116:                                            + (pos + 2));
117:                        }
118:                    } else {
119:                        userSB.append(parseUnquotedLocalPart(address));
120:                        if (userSB.toString().length() == 0) {
121:                            throw new ParseException(
122:                                    "No local-part (user account) found at position "
123:                                            + (pos + 1));
124:                        }
125:                    }
126:
127:                    //find @
128:                    if (pos >= address.length() || address.charAt(pos) != '@') {
129:                        throw new ParseException(
130:                                "Did not find @ between local-part and domain at position "
131:                                        + (pos + 1));
132:                    }
133:                    pos++;
134:
135:                    //parse domain
136:                    //<domain> ::=  <element> | <element> "." <domain>
137:                    //<element> ::= <name> | "#" <number> | "[" <dotnum> "]"
138:                    while (true) {
139:                        if (address.charAt(pos) == '#') {
140:                            hostSB.append(parseNumber(address));
141:                        } else if (address.charAt(pos) == '[') {
142:                            hostSB.append(parseDotNum(address));
143:                        } else {
144:                            hostSB.append(parseDomainName(address));
145:                        }
146:                        if (pos >= address.length()) {
147:                            break;
148:                        }
149:                        if (address.charAt(pos) == '.') {
150:                            hostSB.append('.');
151:                            pos++;
152:                            continue;
153:                        }
154:                        break;
155:                    }
156:
157:                    if (hostSB.toString().length() == 0) {
158:                        throw new ParseException("No domain found at position "
159:                                + (pos + 1));
160:                    }
161:                } catch (IndexOutOfBoundsException ioobe) {
162:                    throw new ParseException("Out of data at position "
163:                            + (pos + 1));
164:                }
165:
166:                user = userSB.toString();
167:                host = hostSB.toString();
168:            }
169:
170:            /**
171:             * Construct a MailAddress with the provided personal name and email
172:             * address.
173:             *
174:             * @param   user        the username or account name on the mail server
175:             * @param   host        the server that should accept messages for this user
176:             * @throws  ParseException    if the parse failed
177:             */
178:            public MailAddress(String newUser, String newHost)
179:                    throws ParseException {
180:                this (newUser + "@" + newHost);
181:            }
182:
183:            /**
184:             * Constructs a MailAddress from a JavaMail InternetAddress, using only the
185:             * email address portion, discarding the personal name.
186:             */
187:            public MailAddress(InternetAddress address) throws ParseException {
188:                this (address.getAddress());
189:            }
190:
191:            /**
192:             * Return the host part.
193:             *
194:             * @return  a <code>String</code> object representing the host part
195:             *          of this email address. If the host is of the dotNum form
196:             *          (e.g. [yyy.yyy.yyy.yyy]) then strip the braces first.
197:             */
198:            public String getHost() {
199:                if (!(host.startsWith("[") && host.endsWith("]"))) {
200:                    return host;
201:                } else {
202:                    return host.substring(1, host.length() - 1);
203:                }
204:            }
205:
206:            /**
207:             * Return the user part.
208:             *
209:             * @return  a <code>String</code> object representing the user part
210:             *          of this email address.
211:             * @throws  AddressException    if the parse failed
212:             */
213:            public String getUser() {
214:                return user;
215:            }
216:
217:            public String toString() {
218:                StringBuffer addressBuffer = new StringBuffer(128).append(user)
219:                        .append("@").append(host);
220:                return addressBuffer.toString();
221:            }
222:
223:            /**
224:             * Return MailAddress as InternetAddress
225:             * 
226:             * @return the address
227:             */
228:            public InternetAddress toInternetAddress() {
229:                try {
230:                    return new InternetAddress(toString());
231:                } catch (javax.mail.internet.AddressException ae) {
232:                    //impossible really
233:                    return null;
234:                }
235:            }
236:
237:            public boolean equals(Object obj) {
238:                if (obj == null) {
239:                    return false;
240:                } else if (obj instanceof  String) {
241:                    String theString = (String) obj;
242:                    return toString().equalsIgnoreCase(theString);
243:                } else if (obj instanceof  MailAddress) {
244:                    MailAddress addr = (MailAddress) obj;
245:                    return getUser().equalsIgnoreCase(addr.getUser())
246:                            && getHost().equalsIgnoreCase(addr.getHost());
247:                }
248:                return false;
249:            }
250:
251:            /**
252:             * Return a hashCode for this object which should be identical for addresses
253:             * which are equivalent.  This is implemented by obtaining the default
254:             * hashcode of the String representation of the MailAddress.  Without this
255:             * explicit definition, the default hashCode will create different hashcodes
256:             * for separate object instances.
257:             *
258:             * @return the hashcode.
259:             */
260:            public int hashCode() {
261:                return toString().toLowerCase(Locale.US).hashCode();
262:            }
263:
264:            private String parseQuotedLocalPart(String address)
265:                    throws ParseException {
266:                StringBuffer resultSB = new StringBuffer();
267:                resultSB.append('\"');
268:                pos++;
269:                //<quoted-string> ::=  """ <qtext> """
270:                //<qtext> ::=  "\" <x> | "\" <x> <qtext> | <q> | <q> <qtext>
271:                while (true) {
272:                    if (address.charAt(pos) == '\"') {
273:                        resultSB.append('\"');
274:                        //end of quoted string... move forward
275:                        pos++;
276:                        break;
277:                    }
278:                    if (address.charAt(pos) == '\\') {
279:                        resultSB.append('\\');
280:                        pos++;
281:                        //<x> ::= any one of the 128 ASCII characters (no exceptions)
282:                        char x = address.charAt(pos);
283:                        if (x < 0 || x > 127) {
284:                            throw new ParseException(
285:                                    "Invalid \\ syntaxed character at position "
286:                                            + (pos + 1));
287:                        }
288:                        resultSB.append(x);
289:                        pos++;
290:                    } else {
291:                        //<q> ::= any one of the 128 ASCII characters except <CR>,
292:                        //<LF>, quote ("), or backslash (\)
293:                        char q = address.charAt(pos);
294:                        if (q <= 0 || q == '\n' || q == '\r' || q == '\"'
295:                                || q == '\\') {
296:                            throw new ParseException(
297:                                    "Unquoted local-part (user account) must be one of the 128 ASCI characters exception <CR>, <LF>, quote (\"), or backslash (\\) at position "
298:                                            + (pos + 1));
299:                        }
300:                        resultSB.append(q);
301:                        pos++;
302:                    }
303:                }
304:                return resultSB.toString();
305:            }
306:
307:            private String parseUnquotedLocalPart(String address)
308:                    throws ParseException {
309:                StringBuffer resultSB = new StringBuffer();
310:                //<dot-string> ::= <string> | <string> "." <dot-string>
311:                boolean lastCharDot = false;
312:                while (true) {
313:                    //<string> ::= <char> | <char> <string>
314:                    //<char> ::= <c> | "\" <x>
315:                    if (address.charAt(pos) == '\\') {
316:                        resultSB.append('\\');
317:                        pos++;
318:                        //<x> ::= any one of the 128 ASCII characters (no exceptions)
319:                        char x = address.charAt(pos);
320:                        if (x < 0 || x > 127) {
321:                            throw new ParseException(
322:                                    "Invalid \\ syntaxed character at position "
323:                                            + (pos + 1));
324:                        }
325:                        resultSB.append(x);
326:                        pos++;
327:                        lastCharDot = false;
328:                    } else if (address.charAt(pos) == '.') {
329:                        resultSB.append('.');
330:                        pos++;
331:                        lastCharDot = true;
332:                    } else if (address.charAt(pos) == '@') {
333:                        //End of local-part
334:                        break;
335:                    } else {
336:                        //<c> ::= any one of the 128 ASCII characters, but not any
337:                        //    <special> or <SP>
338:                        //<special> ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "."
339:                        //    | "," | ";" | ":" | "@"  """ | the control
340:                        //    characters (ASCII codes 0 through 31 inclusive and
341:                        //    127)
342:                        //<SP> ::= the space character (ASCII code 32)
343:                        char c = address.charAt(pos);
344:                        if (c <= 31 || c >= 127 || c == ' ') {
345:                            throw new ParseException(
346:                                    "Invalid character in local-part (user account) at position "
347:                                            + (pos + 1));
348:                        }
349:                        for (int i = 0; i < SPECIAL.length; i++) {
350:                            if (c == SPECIAL[i]) {
351:                                throw new ParseException(
352:                                        "Invalid character in local-part (user account) at position "
353:                                                + (pos + 1));
354:                            }
355:                        }
356:                        resultSB.append(c);
357:                        pos++;
358:                        lastCharDot = false;
359:                    }
360:                }
361:                if (lastCharDot) {
362:                    throw new ParseException(
363:                            "local-part (user account) ended with a \".\", which is invalid.");
364:                }
365:                return resultSB.toString();
366:            }
367:
368:            private String parseNumber(String address) throws ParseException {
369:                //<number> ::= <d> | <d> <number>
370:
371:                StringBuffer resultSB = new StringBuffer();
372:                //We keep the position from the class level pos field
373:                while (true) {
374:                    if (pos >= address.length()) {
375:                        break;
376:                    }
377:                    //<d> ::= any one of the ten digits 0 through 9
378:                    char d = address.charAt(pos);
379:                    if (d == '.') {
380:                        break;
381:                    }
382:                    if (d < '0' || d > '9') {
383:                        throw new ParseException(
384:                                "In domain, did not find a number in # address at position "
385:                                        + (pos + 1));
386:                    }
387:                    resultSB.append(d);
388:                    pos++;
389:                }
390:                return resultSB.toString();
391:            }
392:
393:            private String parseDotNum(String address) throws ParseException {
394:                //throw away all irrelevant '\' they're not necessary for escaping of '.' or digits, and are illegal as part of the domain-literal
395:                while (address.indexOf("\\") > -1) {
396:                    address = address.substring(0, address.indexOf("\\"))
397:                            + address.substring(address.indexOf("\\") + 1);
398:                }
399:                StringBuffer resultSB = new StringBuffer();
400:                //we were passed the string with pos pointing the the [ char.
401:                // take the first char ([), put it in the result buffer and increment pos
402:                resultSB.append(address.charAt(pos));
403:                pos++;
404:
405:                //<dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
406:                for (int octet = 0; octet < 4; octet++) {
407:                    //<snum> ::= one, two, or three digits representing a decimal
408:                    //                      integer value in the range 0 through 255
409:                    //<d> ::= any one of the ten digits 0 through 9
410:                    StringBuffer snumSB = new StringBuffer();
411:                    for (int digits = 0; digits < 3; digits++) {
412:                        char d = address.charAt(pos);
413:                        if (d == '.') {
414:                            break;
415:                        }
416:                        if (d == ']') {
417:                            break;
418:                        }
419:                        if (d < '0' || d > '9') {
420:                            throw new ParseException(
421:                                    "Invalid number at position " + (pos + 1));
422:                        }
423:                        snumSB.append(d);
424:                        pos++;
425:                    }
426:                    if (snumSB.toString().length() == 0) {
427:                        throw new ParseException(
428:                                "Number not found at position " + (pos + 1));
429:                    }
430:                    try {
431:                        int snum = Integer.parseInt(snumSB.toString());
432:                        if (snum > 255) {
433:                            throw new ParseException(
434:                                    "Invalid number at position " + (pos + 1));
435:                        }
436:                    } catch (NumberFormatException nfe) {
437:                        throw new ParseException("Invalid number at position "
438:                                + (pos + 1));
439:                    }
440:                    resultSB.append(snumSB.toString());
441:                    if (address.charAt(pos) == ']') {
442:                        if (octet < 3) {
443:                            throw new ParseException(
444:                                    "End of number reached too quickly at "
445:                                            + (pos + 1));
446:                        } else {
447:                            break;
448:                        }
449:                    }
450:                    if (address.charAt(pos) == '.') {
451:                        resultSB.append('.');
452:                        pos++;
453:                    }
454:                }
455:                if (address.charAt(pos) != ']') {
456:                    throw new ParseException(
457:                            "Did not find closing bracket \"]\" in domain at position "
458:                                    + (pos + 1));
459:                }
460:                resultSB.append(']');
461:                pos++;
462:                return resultSB.toString();
463:            }
464:
465:            private String parseDomainName(String address)
466:                    throws ParseException {
467:                StringBuffer resultSB = new StringBuffer();
468:                //<name> ::= <a> <ldh-str> <let-dig>
469:                //<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
470:                //<let-dig> ::= <a> | <d>
471:                //<let-dig-hyp> ::= <a> | <d> | "-"
472:                //<a> ::= any one of the 52 alphabetic characters A through Z
473:                //  in upper case and a through z in lower case
474:                //<d> ::= any one of the ten digits 0 through 9
475:
476:                // basically, this is a series of letters, digits, and hyphens,
477:                // but it can't start with a digit or hypthen
478:                // and can't end with a hyphen
479:
480:                // in practice though, we should relax this as domain names can start
481:                // with digits as well as letters.  So only check that doesn't start
482:                // or end with hyphen.
483:                while (true) {
484:                    if (pos >= address.length()) {
485:                        break;
486:                    }
487:                    char ch = address.charAt(pos);
488:                    if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z')
489:                            || (ch >= 'A' && ch <= 'Z') || (ch == '-')) {
490:                        resultSB.append(ch);
491:                        pos++;
492:                        continue;
493:                    }
494:                    if (ch == '.') {
495:                        break;
496:                    }
497:                    throw new ParseException("Invalid character at " + pos);
498:                }
499:                String result = resultSB.toString();
500:                if (result.startsWith("-") || result.endsWith("-")) {
501:                    throw new ParseException(
502:                            "Domain name cannot begin or end with a hyphen \"-\" at position "
503:                                    + (pos + 1));
504:                }
505:                return result;
506:            }
507:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.