1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/* 2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Conditions Of Use 3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* 4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* This software was developed by employees of the National Institute of 5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Standards and Technology (NIST), an agency of the Federal Government. 6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Pursuant to title 15 Untied States Code Section 105, works of NIST 7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* employees are not subject to copyright protection in the United States 8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* and are considered to be in the public domain. As a result, a formal 9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* license is not needed to use the software. 10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* 11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* This software is provided by NIST as a service and is expressly 12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED 13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF 14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT 15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* AND DATA ACCURACY. NIST does not warrant or make any representations 16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* regarding the use of the software or the results thereof, including but 17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* not limited to the correctness, accuracy, reliability or usefulness of 18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* the software. 19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* 20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* Permission to use this software is contingent upon your acceptance 21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* of the terms of this agreement 22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* 23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* . 24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang* 25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang*/ 26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.parser; 27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.HostNameParser; 28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.HostPort; 29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.NameValue; 30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.NameValueList; 31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.Token; 32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.GenericURI; 33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.SipUri; 34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.TelURLImpl; 35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.TelephoneNumber; 36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException; 37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/** 39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parser For SIP and Tel URLs. Other kinds of URL's are handled by the 40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * J2SE 1.4 URL class. 41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.27 $ $Date: 2009/10/22 10:27:39 $ 42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/> 44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class URLParser extends Parser { 48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public URLParser(String url) { 50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lexer = new Lexer("sip_urlLexer", url); 51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // public tag added - issued by Miguel Freitas 54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public URLParser(Lexer lexer) { 55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lexer = lexer; 56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lexer.selectLexer("sip_urlLexer"); 57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected static boolean isMark(char next) { 59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (next) { 60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '-': 61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '_': 62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '.': 63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '!': 64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '~': 65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '*': 66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '\'': 67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '(': 68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ')': 69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang default: 71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected static boolean isUnreserved(char next) { 76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return Lexer.isAlphaDigit(next) || isMark(next); 77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected static boolean isReservedNoSlash(char next) { 80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (next) { 81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ';': 82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '?': 83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ':': 84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '@': 85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '&': 86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '+': 87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '$': 88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ',': 89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang default: 91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Missing '=' bug in character set - discovered by interop testing 96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // at SIPIT 13 by Bob Johnson and Scott Holben. 97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // change . to ; by Bruno Konik 98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected static boolean isUserUnreserved(char la) { 99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (la) { 100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '&': 101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '?': 102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '+': 103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '$': 104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '#': 105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '/': 106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ',': 107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ';': 108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '=': 109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang default: 111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String unreserved() throws ParseException { 116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next = lexer.lookAhead(0); 117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isUnreserved(next)) { 118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return String.valueOf(next); 120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("unreserved"); 122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** Name or value of a parameter. 126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String paramNameOrValue() throws ParseException { 128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int startIdx = lexer.getPtr(); 129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next = lexer.lookAhead(0); 131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean isValidChar = false; 132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (next) { 133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '[': 134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ']':// JvB: fixed this one 135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '/': 136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ':': 137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '&': 138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '+': 139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '$': 140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang isValidChar = true; 141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isValidChar || isUnreserved(next)) { 143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isEscaped()) { 145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(3); 146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return lexer.getBuffer().substring(startIdx, lexer.getPtr()); 150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private NameValue uriParam() throws ParseException { 153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("uriParam"); 155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String pvalue = ""; 157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String pname = paramNameOrValue(); 158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next = lexer.lookAhead(0); 159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean isFlagParam = true; 160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (next == '=') { 161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang pvalue = paramNameOrValue(); 163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang isFlagParam = false; 164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (pname.length() == 0 && 166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ( pvalue == null || 167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang pvalue.length() == 0)) 168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else return new NameValue(pname, pvalue, isFlagParam); 170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("uriParam"); 173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected static boolean isReserved(char next) { 177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (next) { 178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ';': 179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '/': 180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '?': 181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ':': 182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '=': // Bug fix by Bruno Konik 183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '@': 184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '&': 185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '+': 186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '$': 187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ',': 188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return true; 189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang default: 190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String reserved() throws ParseException { 195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next = lexer.lookAhead(0); 196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isReserved(next)) { 197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return new StringBuffer().append(next).toString(); 199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("reserved"); 201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected boolean isEscaped() { 204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return lexer.lookAhead(0) == '%' && 206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Lexer.isHexDigit(lexer.lookAhead(1)) && 207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Lexer.isHexDigit(lexer.lookAhead(2)); 208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return false; 210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String escaped() throws ParseException { 214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("escaped"); 216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringBuffer retval = new StringBuffer(); 218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next = lexer.lookAhead(0); 219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next1 = lexer.lookAhead(1); 220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next2 = lexer.lookAhead(2); 221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (next == '%' 222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && Lexer.isHexDigit(next1) 223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && Lexer.isHexDigit(next2)) { 224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(3); 225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(next); 226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(next1); 227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(next2); 228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("escaped"); 230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval.toString(); 231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("escaped"); 234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String mark() throws ParseException { 238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("mark"); 240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char next = lexer.lookAhead(0); 242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isMark(next)) { 243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return new String( new char[]{next} ); 245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("mark"); 247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("mark"); 250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String uric() { 254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("uric"); 256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isUnreserved(la)) { 260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return Lexer.charAsString(la); 262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isReserved(la)) { 263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return Lexer.charAsString(la); 265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isEscaped()) { 266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String retval = lexer.charAsString(3); 267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(3); 268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (Exception ex) { 272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("uric"); 277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String uricNoSlash() { 282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("uricNoSlash"); 284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isEscaped()) { 288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String retval = lexer.charAsString(3); 289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(3); 290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isUnreserved(la)) { 292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return Lexer.charAsString(la); 294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isReservedNoSlash(la)) { 295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return Lexer.charAsString(la); 297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (ParseException ex) { 300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("uricNoSlash"); 305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String uricString() throws ParseException { 309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringBuffer retval = new StringBuffer(); 310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (true) { 311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String next = uric(); 312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (next == null) { 313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: allow IPv6 addresses in generic URI strings 315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // e.g. http://[::1] 316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( la == '[' ) { 317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang HostNameParser hnp = new HostNameParser(this.getLexer()); 318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang HostPort hp = hnp.hostPort( false ); 319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(hp.toString()); 320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang continue; 321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(next); 325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval.toString(); 327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parse and return a structure for a generic URL. 331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Note that non SIP URLs are just stored as a string (not parsed). 332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return URI is a URL structure for a SIP url. 333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @throws ParseException if there was a problem parsing. 334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public GenericURI uriReference( boolean inBrackets ) throws ParseException { 336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("uriReference"); 338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang GenericURI retval = null; 339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token[] tokens = lexer.peekNextToken(2); 340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token t1 = (Token) tokens[0]; 341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token t2 = (Token) tokens[1]; 342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (t1.getTokenType() == TokenTypes.SIP || 345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang t1.getTokenType() == TokenTypes.SIPS) { 346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (t2.getTokenType() == ':') 347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval = sipURL( inBrackets ); 348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("Expecting \':\'"); 350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (t1.getTokenType() == TokenTypes.TEL) { 351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (t2.getTokenType() == ':') { 352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval = telURL( inBrackets ); 353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("Expecting \':\'"); 355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String urlString = uricString(); 357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval = new GenericURI(urlString); 359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (ParseException ex) { 360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException(ex.getMessage()); 361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("uriReference"); 366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parser for the base phone number. 372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private String base_phone_number() throws ParseException { 374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringBuffer s = new StringBuffer(); 375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("base_phone_number"); 378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int lc = 0; 380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char w = lexer.lookAhead(0); 382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (Lexer.isDigit(w) 383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || w == '-' 384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || w == '.' 385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || w == '(' 386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || w == ')') { 387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang s.append(w); 389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lc++; 390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (lc > 0) 391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("unexpected " + w); 394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return s.toString(); 396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("base_phone_number"); 399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parser for the local phone #. 405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private String local_number() throws ParseException { 407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringBuffer s = new StringBuffer(); 408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("local_number"); 410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int lc = 0; 412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (la == '*' 415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '#' 416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '-' 417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '.' 418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '(' 419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == ')' 420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: allow 'A'..'F', should be uppercase 421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || Lexer.isHexDigit(la)) { 422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang s.append(la); 424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lc++; 425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (lc > 0) 426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("unexepcted " + la); 429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return s.toString(); 431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("local_number"); 434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parser for telephone subscriber. 440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return the parsed telephone number. 442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public final TelephoneNumber parseTelephoneNumber( boolean inBrackets ) 444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throws ParseException { 445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TelephoneNumber tn; 446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("telephone_subscriber"); 449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.selectLexer("charLexer"); 450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char c = lexer.lookAhead(0); 452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (c == '+') 453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn = global_phone_number( inBrackets ); 454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else if ( 455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Lexer.isHexDigit(c)// see RFC3966 456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || c == '#' 457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || c == '*' 458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || c == '-' 459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || c == '.' 460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || c == '(' 461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || c == ')' ) { 462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn = local_phone_number( inBrackets ); 463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw createParseException("unexpected char " + c); 465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return tn; 466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("telephone_subscriber"); 469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private final TelephoneNumber global_phone_number( boolean inBrackets ) throws ParseException { 474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("global_phone_number"); 476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TelephoneNumber tn = new TelephoneNumber(); 478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn.setGlobal(true); 479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValueList nv = null; 480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lexer.match(PLUS); 481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String b = base_phone_number(); 482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn.setPhoneNumber(b); 483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lexer.hasMoreChars()) { 484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char tok = lexer.lookAhead(0); 485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (tok == ';' && inBrackets) { 486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lexer.consume(1); 487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nv = tel_parameters(); 488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn.setParameters(nv); 489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return tn; 492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("global_phone_number"); 495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private TelephoneNumber local_phone_number( boolean inBrackets ) throws ParseException { 499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("local_phone_number"); 501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TelephoneNumber tn = new TelephoneNumber(); 502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn.setGlobal(false); 503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValueList nv = null; 504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String b = null; 505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang b = local_number(); 507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn.setPhoneNumber(b); 508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lexer.hasMoreChars()) { 509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token tok = this.lexer.peekNextToken(); 510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (tok.getTokenType()) { 511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case SEMICOLON: 512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang { 513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (inBrackets) { 514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.lexer.consume(1); 515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nv = tel_parameters(); 516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang tn.setParameters(nv); 517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang default : 521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang { 522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("local_phone_number"); 529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return tn; 531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private NameValueList tel_parameters() throws ParseException { 534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValueList nvList = new NameValueList(); 535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: Need to handle 'phone-context' specially 537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // 'isub' (or 'ext') MUST appear first, but we accept any order here 538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValue nv; 539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while ( true ) { 540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String pname = paramNameOrValue(); 541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Handle 'phone-context' specially, it may start with '+' 543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( pname.equalsIgnoreCase("phone-context")) { 544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nv = phone_context(); 545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lexer.lookAhead(0) == '=') { 547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String value = paramNameOrValue(); 549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nv = new NameValue( pname, value, false ); 550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nv = new NameValue( pname, "", true );// flag param 552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang nvList.set( nv ); 555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( lexer.lookAhead(0) == ';' ) { 557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return nvList; 560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parses the 'phone-context' parameter in tel: URLs 567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @throws ParseException 568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private NameValue phone_context() throws ParseException { 570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.match('='); 571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Object value; 574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (la=='+') {// global-number-digits 575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1);// skip '+' 576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang value = "+" + base_phone_number(); 577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if ( Lexer.isAlphaDigit(la) ) { 578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token t = lexer.match( Lexer.ID );// more broad than allowed 579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang value = t.getTokenValue(); 580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new ParseException( "Invalid phone-context:" + la , -1 ); 582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return new NameValue( "phone-context", value, false ); 584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parse and return a structure for a Tel URL. 588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return a parsed tel url structure. 589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public TelURLImpl telURL( boolean inBrackets ) throws ParseException { 591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.match(TokenTypes.TEL); 592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.match(':'); 593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TelephoneNumber tn = this.parseTelephoneNumber(inBrackets); 594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang TelURLImpl telUrl = new TelURLImpl(); 595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang telUrl.setTelephoneNumber(tn); 596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return telUrl; 597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parse and return a structure for a SIP URL. 602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return a URL structure for a SIP url. 603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @throws ParseException if there was a problem parsing. 604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public SipUri sipURL( boolean inBrackets ) throws ParseException { 606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("sipURL"); 608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang SipUri retval = new SipUri(); 609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // pmusgrave - handle sips case 610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token nextToken = lexer.peekNextToken(); 611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int sipOrSips = TokenTypes.SIP; 612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String scheme = TokenNames.SIP; 613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( nextToken.getTokenType() == TokenTypes.SIPS) 614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang { 615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang sipOrSips = TokenTypes.SIPS; 616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang scheme = TokenNames.SIPS; 617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.match(sipOrSips); 621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.match(':'); 622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.setScheme(scheme); 623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int startOfUser = lexer.markInputPosition(); 624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String userOrHost = user();// Note: user may contain ';', host may not... 625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String passOrPort = null; 626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // name:password or host:port 628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( lexer.lookAhead() == ':' ) { 629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang passOrPort = password(); 631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // name@hostPort 634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if ( lexer.lookAhead() == '@' ) { 635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.setUser( userOrHost ); 637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (passOrPort!=null) retval.setUserPassword( passOrPort ); 638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else { 639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // then userOrHost was a host, backtrack just in case a ';' was eaten... 640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.rewindInputPosition( startOfUser ); 641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang HostNameParser hnp = new HostNameParser(this.getLexer()); 644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang HostPort hp = hnp.hostPort( false ); 645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.setHostPort(hp); 646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.selectLexer("charLexer"); 648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // If the URI is not enclosed in brackets, parameters belong to header 650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lexer.lookAhead(0) != ';' || !inBrackets) 651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValue parms = uriParam(); 654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (parms != null) retval.setUriParameter(parms); 655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lexer.hasMoreChars() && lexer.lookAhead(0) == '?') { 658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang NameValue parms = qheader(); 661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.setQHeader(parms); 662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (lexer.hasMoreChars() && lexer.lookAhead(0) != '&') 663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang else 665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 669b23dbfce7ea84c39cea75b612868a5832cb9af2bChia-chi Yeh // BEGIN android-added 670b23dbfce7ea84c39cea75b612868a5832cb9af2bChia-chi Yeh } catch (RuntimeException e) { 671b23dbfce7ea84c39cea75b612868a5832cb9af2bChia-chi Yeh throw new ParseException("Invalid URL: " + lexer.getBuffer(), -1); 672b23dbfce7ea84c39cea75b612868a5832cb9af2bChia-chi Yeh // END android-added 673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("sipURL"); 676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public String peekScheme() throws ParseException { 680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Token[] tokens = lexer.peekNextToken(1); 681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (tokens.length == 0) 682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return null; 683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String scheme = ((Token) tokens[0]).getTokenValue(); 684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return scheme; 685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Get a name value for a given query header (ie one that comes 689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * after the ?). 690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected NameValue qheader() throws ParseException { 692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String name = lexer.getNextToken('='); 693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String value = hvalue(); 695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return new NameValue(name, value, false); 696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String hvalue() throws ParseException { 700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringBuffer retval = new StringBuffer(); 701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Look for a character that can terminate a URL. 704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean isValidChar = false; 705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (la) { 706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '+': 707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '?': 708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ':': 709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '[': 710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ']': 711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '/': 712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '$': 713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '_': 714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '-': 715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '"': 716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '!': 717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '~': 718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '*': 719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '.': 720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '(': 721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ')': 722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang isValidChar = true; 723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isValidChar || Lexer.isAlphaDigit(la)) { 725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(la); 727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (la == '%') { 728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(escaped()); 729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval.toString(); 733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Scan forward until you hit a terminating character for a URL. 737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * We do not handle non sip urls in this implementation. 738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @return the string that takes us to the end of this URL (i.e. to 739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the next delimiter). 740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String urlString() throws ParseException { 742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang StringBuffer retval = new StringBuffer(); 743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.selectLexer("charLexer"); 744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Look for a character that can terminate a URL. 748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (la == ' ' 749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '\t' 750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '\n' 751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '>' 752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang || la == '<') 753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(0); 755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang retval.append(la); 756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval.toString(); 758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String user() throws ParseException { 761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_enter("user"); 763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int startIdx = lexer.getPtr(); 765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (lexer.hasMoreChars()) { 766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isUnreserved(la) || isUserUnreserved(la)) { 768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isEscaped()) { 770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(3); 771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return lexer.getBuffer().substring(startIdx, lexer.getPtr()); 775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } finally { 776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (debug) 777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang dbg_leave("user"); 778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected String password() throws ParseException { 783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int startIdx = lexer.getPtr(); 784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (true) { 785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang char la = lexer.lookAhead(0); 786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean isValidChar = false; 787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang switch (la) { 788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '&': 789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '=': 790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '+': 791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case '$': 792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang case ',': 793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang isValidChar = true; 794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (isValidChar || isUnreserved(la)) { 796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(1); 797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else if (isEscaped()) { 798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang lexer.consume(3); // bug reported by 799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Jeff Haynie 800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } else 801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang break; 802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return lexer.getBuffer().substring(startIdx, lexer.getPtr()); 805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Default parse method. This method just calls uriReference. 809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public GenericURI parse() throws ParseException { 811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return uriReference( true ); 812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // quick test routine for debugging type assignment 815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public static void main(String[] args) throws ParseException 816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang { 817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // quick test for sips parsing 818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang String[] test = { "sip:alice@example.com", 819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "sips:alice@examples.com" , 820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang "sip:3Zqkv5dajqaaas0tCjCxT0xH2ZEuEMsFl0xoasip%3A%2B3519116786244%40siplab.domain.com@213.0.115.163:7070"}; 821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang for ( int i = 0; i < test.length; i++) 823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang { 824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang URLParser p = new URLParser(test[i]); 825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang GenericURI uri = p.parse(); 827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang System.out.println("uri type returned " + uri.getClass().getName()); 828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang System.out.println(test[i] + " is SipUri? " + uri.isSipURI() 829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang + ">" + uri.encode()); 830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang /** 834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang **/ 836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 838