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 Wang
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*******************************************************************************
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)        *
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ******************************************************************************/
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.parser;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.Host;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.HostNameParser;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SIPConstants;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.AddressImpl;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.GenericURI;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.SipUri;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.TelephoneNumber;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.*;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPMessage;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPRequest;
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPResponse;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.UnsupportedEncodingException;
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Acknowledgement: 1/12/2007: Yanick Belanger rewrote the parsing loops to make them
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * simpler and quicker.
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Parse SIP message and parts of SIP messages such as URI's etc from memory and
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * return a structure. Intended use: UDP message processing. This class is used
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * when you have an entire SIP message or SIPHeader or SIP URL in memory and you
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * want to generate a parsed structure from it. For SIP messages, the payload
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * can be binary or String. If you have a binary payload, use
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * parseSIPMessage(byte[]) else use parseSIPMessage(String) The payload is
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * accessible from the parsed message using the getContent and getContentBytes
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * methods provided by the SIPMessage class. If SDP parsing is enabled using the
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * parseContent method, then the SDP body is also parsed and can be accessed
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * from the message using the getSDPAnnounce method. Currently only eager
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * parsing of the message is supported (i.e. the entire message is parsed in one
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * feld swoop).
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.26 $ $Date: 2009/10/22 10:27:38 $
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang  *
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class StringMsgParser {
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean readBody;
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ParseExceptionListener parseExceptionListener;
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String rawStringMessage;
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean strict;
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static boolean computeContentLengthFromMessage = false;
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @since v0.9
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public StringMsgParser() {
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super();
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        readBody = true;
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor (given a parse exception handler).
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @since 1.0
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param exhandler
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is the parse exception listener for the message parser.
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public StringMsgParser(ParseExceptionListener exhandler) {
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this();
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        parseExceptionListener = exhandler;
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Add a handler for header parsing errors.
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param pexhandler
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is a class that implements the ParseExceptionListener
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            interface.
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setParseExceptionListener(ParseExceptionListener pexhandler) {
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        parseExceptionListener = pexhandler;
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a buffer containing a single SIP Message where the body is an array
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * of un-interpreted bytes. This is intended for parsing the message from a
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * memory buffer when the buffer. Incorporates a bug fix for a bug that was
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * noted by Will Sullin of Callcast
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param msgBuffer
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            a byte buffer containing the messages to be parsed. This can
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            consist of multiple SIP Messages concatenated together.
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a SIPMessage[] structure (request or response) containing the
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         parsed SIP message.
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                is thrown when an illegal message has been encountered
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                (and the rest of the buffer is discarded).
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see ParseExceptionListener
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPMessage parseSIPMessage(byte[] msgBuffer) throws ParseException {
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (msgBuffer == null || msgBuffer.length == 0)
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int i = 0;
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Squeeze out any leading control character.
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (msgBuffer[i] < 0x20)
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                i++;
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        catch (ArrayIndexOutOfBoundsException e) {
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Array contains only control char, return null.
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Iterate thru the request/status line and headers.
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String currentLine = null;
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String currentHeader = null;
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean isFirstLine = true;
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPMessage message = null;
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        do
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        {
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int lineStart = i;
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Find the length of the line.
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (msgBuffer[i] != '\r' && msgBuffer[i] != '\n')
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    i++;
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            catch (ArrayIndexOutOfBoundsException e) {
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // End of the message.
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                break;
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int lineLength = i - lineStart;
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Make it a String.
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                currentLine = new String(msgBuffer, lineStart, lineLength, "UTF-8");
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (UnsupportedEncodingException e) {
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new ParseException("Bad message encoding!", 0);
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentLine = trimEndOfLine(currentLine);
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (currentLine.length() == 0) {
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Last header line, process the previous buffered header.
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentHeader != null && message != null) {
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     processHeader(currentHeader, message);
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 }
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else {
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (isFirstLine) {
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    message = processFirstLine(currentLine);
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    char firstChar = currentLine.charAt(0);
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (firstChar == '\t' || firstChar == ' ') {
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (currentHeader == null)
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            throw new ParseException("Bad header continuation.", 0);
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // This is a continuation, append it to the previous line.
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        currentHeader += currentLine.substring(1);
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    else {
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (currentHeader != null && message != null) {
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                             processHeader(currentHeader, message);
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                         }
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        currentHeader = currentLine;
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (msgBuffer[i] == '\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\n')
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                i++;
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            i++;
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            isFirstLine = false;
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } while (currentLine.length() > 0); // End do - while
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (message == null) throw new ParseException("Bad message", 0);
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        message.setSize(i);
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (readBody && message.getContentLength() != null &&
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                message.getContentLength().getContentLength() != 0) {
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int bodyLength = msgBuffer.length - i;
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            byte[] body = new byte[bodyLength];
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            System.arraycopy(msgBuffer, i, body, 0, bodyLength);
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            message.setMessageContent(body,computeContentLengthFromMessage ,message.getContentLength().getContentLength() );
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return message;
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a buffer containing one or more SIP Messages and return an array of
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * SIPMessage parsed structures.
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param msgString
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            a String containing the messages to be parsed. This can
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            consist of multiple SIP Messages concatenated together.
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a SIPMessage structure (request or response) containing the
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         parsed SIP message.
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                is thrown when an illegal message has been encountered
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                (and the rest of the buffer is discarded).
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see ParseExceptionListener
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPMessage parseSIPMessage(String msgString) throws ParseException {
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (msgString == null || msgString.length() == 0)
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        rawStringMessage = msgString;
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int i = 0;
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Squeeze out any leading control character.
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (msgString.charAt(i) < 0x20)
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                i++;
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        catch (ArrayIndexOutOfBoundsException e) {
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Array contains only control char, return null.
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (StringIndexOutOfBoundsException ex) {
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Iterate thru the request/status line and headers.
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String currentLine = null;
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String currentHeader = null;
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean isFirstLine = true;
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPMessage message = null;
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        do
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        {
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int lineStart = i;
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Find the length of the line.
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                char c = msgString.charAt(i);
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (c != '\r' && c != '\n')
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    c = msgString.charAt(++i);
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            catch (ArrayIndexOutOfBoundsException e) {
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // End of the message.
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                break;
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch ( StringIndexOutOfBoundsException ex) {
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                break;
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Make it a String.
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentLine = msgString.substring(lineStart, i);
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentLine = trimEndOfLine(currentLine);
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (currentLine.length() == 0) {
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Last header line, process the previous buffered header.
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentHeader != null) {
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    processHeader(currentHeader, message);
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else {
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (isFirstLine) {
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    message = processFirstLine(currentLine);
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    char firstChar = currentLine.charAt(0);
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (firstChar == '\t' || firstChar == ' ') {
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (currentHeader == null)
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            throw new ParseException("Bad header continuation.", 0);
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // This is a continuation, append it to the previous line.
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        currentHeader += currentLine.substring(1);
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    else {
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (currentHeader != null) {
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            processHeader(currentHeader, message);
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        currentHeader = currentLine;
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (msgString.charAt(i) == '\r' && msgString.length() > i+1 && msgString.charAt(i+1) == '\n')
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                i++;
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            i++;
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            isFirstLine = false;
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (currentLine.length() > 0);
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        message.setSize(i);
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Check for content legth header
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (readBody && message.getContentLength() != null ) {
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if ( message.getContentLength().getContentLength() != 0) {
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String body = msgString.substring(i);
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                message.setMessageContent(body,this.strict,computeContentLengthFromMessage,message.getContentLength().getContentLength());
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             } else if (!computeContentLengthFromMessage && message.getContentLength().getContentLength() == 0 && !msgString.endsWith("\r\n\r\n") ){
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 if ( strict ) {
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                     throw new ParseException("Extraneous characters at the end of the message ",i);
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 }
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             }
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return message;
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String trimEndOfLine(String line) {
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (line == null)
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return line;
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int i = line.length() - 1;
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (i >= 0 && line.charAt(i) <= 0x20)
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            i--;
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (i == line.length() - 1)
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return line;
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (i == -1)
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return "";
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return line.substring(0, i+1);
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private SIPMessage processFirstLine(String firstLine) throws ParseException {
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPMessage message;
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) {
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            message = new SIPRequest();
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                RequestLine requestLine = new RequestLineParser(firstLine + "\n")
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .parse();
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ((SIPRequest) message).setRequestLine(requestLine);
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (ParseException ex) {
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.parseExceptionListener != null)
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.parseExceptionListener.handleException(ex, message,
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            RequestLine.class, firstLine, rawStringMessage);
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                else
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw ex;
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            message = new SIPResponse();
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                StatusLine sl = new StatusLineParser(firstLine + "\n").parse();
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ((SIPResponse) message).setStatusLine(sl);
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (ParseException ex) {
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.parseExceptionListener != null) {
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.parseExceptionListener.handleException(ex, message,
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            StatusLine.class, firstLine, rawStringMessage);
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw ex;
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return message;
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void processHeader(String header, SIPMessage message) throws ParseException {
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (header == null || header.length() == 0)
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HeaderParser headerParser = null;
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            headerParser = ParserFactory.createParser(header + "\n");
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException ex) {
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.parseExceptionListener.handleException(ex, message, null,
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    header, rawStringMessage);
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPHeader sipHeader = headerParser.parse();
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            message.attachHeader(sipHeader, false);
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException ex) {
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.parseExceptionListener != null) {
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String headerName = Lexer.getHeaderName(header);
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Class headerClass = NameMap.getClassFromName(headerName);
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (headerClass == null) {
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    headerClass = ExtensionHeaderImpl.class;
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.parseExceptionListener.handleException(ex, message,
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        headerClass, header, rawStringMessage);
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse an address (nameaddr or address spec) and return and address
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * structure.
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param address
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is a String containing the address to be parsed.
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a parsed address structure.
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @since v1.0
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                when the address is badly formatted.
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public AddressImpl parseAddress(String address) throws ParseException {
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        AddressParser addressParser = new AddressParser(address);
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return addressParser.address(true);
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a host:port and return a parsed structure.
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param hostport
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is a String containing the host:port to be parsed
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a parsed address structure.
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @since v1.0
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception throws
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                a ParseException when the address is badly formatted.
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public HostPort parseHostPort(String hostport) throws ParseException {
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Lexer lexer = new Lexer("charLexer", hostport);
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new HostNameParser(lexer).hostPort();
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    */
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a host name and return a parsed structure.
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param host
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is a String containing the host name to be parsed
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a parsed address structure.
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @since v1.0
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                a ParseException when the hostname is badly formatted.
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Host parseHost(String host) throws ParseException {
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Lexer lexer = new Lexer("charLexer", host);
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new HostNameParser(lexer).host();
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a telephone number return a parsed structure.
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param telephone_number
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            is a String containing the telephone # to be parsed
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a parsed address structure.
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @since v1.0
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                a ParseException when the address is badly formatted.
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public TelephoneNumber parseTelephoneNumber(String telephone_number)
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws ParseException {
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Bug fix contributed by Will Scullin
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new URLParser(telephone_number).parseTelephoneNumber(true);
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a SIP url from a string and return a URI structure for it.
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param url
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            a String containing the URI structure to be parsed.
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A parsed URI structure
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                if there was an error parsing the message.
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SipUri parseSIPUrl(String url) throws ParseException {
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return new URLParser(url).sipURL(true);
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ClassCastException ex) {
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(url + " Not a SIP URL ", 0);
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse a uri from a string and return a URI structure for it.
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param url
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            a String containing the URI structure to be parsed.
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A parsed URI structure
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                if there was an error parsing the message.
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public GenericURI parseUrl(String url) throws ParseException {
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new URLParser(url).parse();
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse an individual SIP message header from a string.
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param header
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            String containing the SIP header.
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a SIPHeader structure.
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                if there was an error parsing the message.
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPHeader parseSIPHeader(String header) throws ParseException {
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int start = 0;
530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int end = header.length() - 1;
531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Squeeze out any leading control character.
533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (header.charAt(start) <= 0x20)
534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                start++;
535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Squeeze out any trailing control character.
537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (header.charAt(end) <= 0x20)
538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                end--;
539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        catch (ArrayIndexOutOfBoundsException e) {
541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Array contains only control char.
542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("Empty header.", 0);
543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer buffer = new StringBuffer(end + 1);
546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int i = start;
547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int lineStart = start;
548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean endOfLine = false;
549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (i <= end) {
550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            char c = header.charAt(i);
551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (c == '\r' || c == '\n') {
552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!endOfLine) {
553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    buffer.append(header.substring(lineStart, i));
554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    endOfLine = true;
555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else {
558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (endOfLine) {
559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    endOfLine = false;
560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (c == ' ' || c == '\t') {
561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        buffer.append(' ');
562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lineStart = i + 1;
563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    else {
565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        lineStart = i;
566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            i++;
571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        buffer.append(header.substring(lineStart, i));
573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        buffer.append('\n');
574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HeaderParser hp = ParserFactory.createParser(buffer.toString());
576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (hp == null)
577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("could not create parser", 0);
578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return hp.parse();
579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse the SIP Request Line
583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param requestLine
585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            a String containing the request line to be parsed.
586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a RequestLine structure that has the parsed RequestLine
587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                if there was an error parsing the requestLine.
589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public RequestLine parseSIPRequestLine(String requestLine)
592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws ParseException {
593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        requestLine += "\n";
594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new RequestLineParser(requestLine).parse();
595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Parse the SIP Response message status line
599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param statusLine
601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            a String containing the Status line to be parsed.
602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return StatusLine class corresponding to message
603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @exception ParseException
604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *                if there was an error parsing
605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see StatusLine
606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public StatusLine parseSIPStatusLine(String statusLine)
609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throws ParseException {
610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        statusLine += "\n";
611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return new StatusLineParser(statusLine).parse();
612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static void setComputeContentLengthFromMessage(
615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean computeContentLengthFromMessage) {
616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringMsgParser.computeContentLengthFromMessage = computeContentLengthFromMessage;
617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Test code.
623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static void main(String[] args) throws ParseException {
625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String messages[] = {
626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "SIP/2.0 200 OK\r\n"
627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "To: \"The Little Blister\" <sip:LittleGuy@there.com>;tag=469bc066\r\n"
628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "From: \"The Master Blaster\" <sip:BigGuy@here.com>;tag=11\r\n"
629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Via: SIP/2.0/UDP 139.10.134.246:5060;branch=z9hG4bK8b0a86f6_1030c7d18e0_17;received=139.10.134.246\r\n"
630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Call-ID: 1030c7d18ae_a97b0b_b@8b0a86f6\r\n"
631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "CSeq: 1 SUBSCRIBE\r\n"
632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Contact: <sip:172.16.11.162:5070>\r\n"
633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Content-Length: 0\r\n\r\n",
634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "SIP/2.0 180 Ringing\r\n"
636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Via: SIP/2.0/UDP 172.18.1.29:5060;branch=z9hG4bK43fc10fb4446d55fc5c8f969607991f4\r\n"
637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "To: \"0440\" <sip:0440@212.209.220.131>;tag=2600\r\n"
638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "From: \"Andreas\" <sip:andreas@e-horizon.se>;tag=8524\r\n"
639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Call-ID: f51a1851c5f570606140f14c8eb64fd3@172.18.1.29\r\n"
640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "CSeq: 1 INVITE\r\n" + "Max-Forwards: 70\r\n"
641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Record-Route: <sip:212.209.220.131:5060>\r\n"
642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Content-Length: 0\r\n\r\n",
643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                "REGISTER sip:nist.gov SIP/2.0\r\n"
644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Via: SIP/2.0/UDP 129.6.55.182:14826\r\n"
645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Max-Forwards: 70\r\n"
646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "From: <sip:mranga@nist.gov>;tag=6fcd5c7ace8b4a45acf0f0cd539b168b;epid=0d4c418ddf\r\n"
647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "To: <sip:mranga@nist.gov>\r\n"
648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Call-ID: c5679907eb954a8da9f9dceb282d7230@129.6.55.182\r\n"
649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "CSeq: 1 REGISTER\r\n"
650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Contact: <sip:129.6.55.182:14826>;methods=\"INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER\"\r\n"
651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "User-Agent: RTC/(Microsoft RTC)\r\n"
652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Event:  registration\r\n"
653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Allow-Events: presence\r\n"
654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Content-Length: 0\r\n\r\n"
655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "INVITE sip:littleguy@there.com:5060 SIP/2.0\r\n"
656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Via: SIP/2.0/UDP 65.243.118.100:5050\r\n"
657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "From: M. Ranganathan  <sip:M.Ranganathan@sipbakeoff.com>;tag=1234\r\n"
658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "To: \"littleguy@there.com\" <sip:littleguy@there.com:5060> \r\n"
659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Call-ID: Q2AboBsaGn9!?x6@sipbakeoff.com \r\n"
660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "CSeq: 1 INVITE \r\n"
661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "Content-Length: 247\r\n\r\n"
662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "v=0\r\n"
663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "o=4855 13760799956958020 13760799956958020 IN IP4  129.6.55.78\r\n"
664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "s=mysession session\r\n" + "p=+46 8 52018010\r\n"
665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "c=IN IP4  129.6.55.78\r\n" + "t=0 0\r\n"
666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "m=audio 6022 RTP/AVP 0 4 18\r\n"
667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "a=rtpmap:0 PCMU/8000\r\n"
668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "a=rtpmap:4 G723/8000\r\n"
669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + "a=rtpmap:18 G729A/8000\r\n" + "a=ptime:20\r\n" };
670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        class ParserThread implements Runnable {
672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String[] messages;
673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            public ParserThread(String[] messagesToParse) {
675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.messages = messagesToParse;
676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            public void run() {
679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                for (int i = 0; i < messages.length; i++) {
680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    StringMsgParser smp = new StringMsgParser();
681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SIPMessage sipMessage = smp
683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                .parseSIPMessage(messages[i]);
684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        System.out.println(" i = " + i + " branchId = "
685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + sipMessage.getTopmostVia().getBranch());
686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // System.out.println("encoded " +
687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // sipMessage.toString());
688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (ParseException ex) {
689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // System.out.println("dialog id = " +
693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // sipMessage.getDialogId(false));
694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        for (int i = 0; i < 20; i++) {
699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            new Thread(new ParserThread(messages)).start();
700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setStrict(boolean strict) {
705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang       this.strict = strict;
706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
710