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 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *******************************************************************************/
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.message;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.address.*;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.*;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.HashSet;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Hashtable;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.LinkedList;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Set;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.UnsupportedEncodingException;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Iterator;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.URI;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.*;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.text.ParseException;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.*;
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.*;
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.*;
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.stack.SIPTransactionStack;
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Acknowledgements: Mark Bednarek made a few fixes to this code. Jeff Keyser added two methods
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * that create responses and generate cancel requests from incoming orignial requests without the
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * additional overhead of encoding and decoding messages. Bruno Konik noticed an extraneous
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * newline added to the end of the buffer when encoding it. Incorporates a bug report from Andreas
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Bystrom. Szabo Barna noticed a contact in a cancel request - this is a pointless header for
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * cancel. Antonis Kyardis contributed bug fixes. Jeroen van Bemmel noted that method names are
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * case sensitive, should use equals() in getting CannonicalName
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * The SIP Request structure.
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.52 $ $Date: 2009/12/16 14:58:40 $
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @since 1.1
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic final class SIPRequest extends SIPMessage implements javax.sip.message.Request, RequestExt {
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final long serialVersionUID = 3360720013577322927L;
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final String DEFAULT_USER = "ip";
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final String DEFAULT_TRANSPORT = "udp";
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private transient Object transactionPointer;
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private RequestLine requestLine;
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private transient Object messageChannel;
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private transient Object inviteTransaction; // The original invite request for a
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // given cancel request
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set of target refresh methods, currently: INVITE, UPDATE, SUBSCRIBE, NOTIFY, REFER
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A target refresh request and its response MUST have a Contact
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final Set<String> targetRefreshMethods = new HashSet<String>();
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A table that maps a name string to its cannonical constant. This is used to speed up
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * parsing of messages .equals reduces to == if we use the constant value.
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static final Hashtable<String, String> nameTable = new Hashtable<String, String>();
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private static void putName(String name) {
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        nameTable.put(name, name);
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    static {
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetRefreshMethods.add(Request.INVITE);
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetRefreshMethods.add(Request.UPDATE);
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetRefreshMethods.add(Request.SUBSCRIBE);
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetRefreshMethods.add(Request.NOTIFY);
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetRefreshMethods.add(Request.REFER);
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.INVITE);
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.BYE);
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.CANCEL);
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.ACK);
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.PRACK);
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.INFO);
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.MESSAGE);
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.NOTIFY);
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.OPTIONS);
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.PRACK);
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.PUBLISH);
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.REFER);
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.REGISTER);
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.SUBSCRIBE);
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        putName(Request.UPDATE);
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true iff the method is a target refresh
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static boolean isTargetRefresh(String ucaseMethod) {
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return targetRefreshMethods.contains(ucaseMethod);
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true iff the method is a dialog creating method
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static boolean isDialogCreating(String ucaseMethod) {
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return SIPTransactionStack.isDialogCreated(ucaseMethod);
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set to standard constants to speed up processing. this makes equals comparisons run much
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * faster in the stack because then it is just identity comparision. Character by char
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * comparison is not required. The method returns the String CONSTANT corresponding to the
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * String name.
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static String getCannonicalName(String method) {
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (nameTable.containsKey(method))
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return (String) nameTable.get(method);
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return method;
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the Request Line of the SIPRequest.
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the request line of the SIP Request.
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public RequestLine getRequestLine() {
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return requestLine;
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the request line of the SIP Request.
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param requestLine is the request line to set in the SIP Request.
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setRequestLine(RequestLine requestLine) {
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.requestLine = requestLine;
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Constructor.
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPRequest() {
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        super();
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Convert to a formatted string for pretty printing. Note that the encode method converts
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * this into a sip message that is suitable for transmission. Note hack here if you want to
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * convert the nice curly brackets into some grotesque XML tag.
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a string which can be used to examine the message contents.
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String debugDump() {
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String superstring = super.debugDump();
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        stringRepresentation = "";
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        sprint(SIPRequest.class.getName());
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        sprint("{");
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine != null)
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            sprint(requestLine.debugDump());
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        sprint(superstring);
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        sprint("}");
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return stringRepresentation;
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Check header for constraints. (1) Invite options and bye requests can only have SIP URIs in
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the contact headers. (2) Request must have cseq, to and from and via headers. (3) Method in
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * request URI must match that in CSEQ.
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void checkHeaders() throws ParseException {
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String prefix = "Missing a required header : ";
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /* Check for required headers */
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getCSeq() == null) {
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(prefix + CSeqHeader.NAME, 0);
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getTo() == null) {
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(prefix + ToHeader.NAME, 0);
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.callIdHeader == null || this.callIdHeader.getCallId() == null
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || callIdHeader.getCallId().equals("")) {
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(prefix + CallIdHeader.NAME, 0);
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getFrom() == null) {
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(prefix + FromHeader.NAME, 0);
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getViaHeaders() == null) {
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(prefix + ViaHeader.NAME, 0);
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2374842dc6980fb830a4eef822e7d85beaab79ce2d2Chia-chi Yeh        // BEGIN android-deleted
2384842dc6980fb830a4eef822e7d85beaab79ce2d2Chia-chi Yeh        /*
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getMaxForwards() == null) {
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException(prefix + MaxForwardsHeader.NAME, 0);
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2424842dc6980fb830a4eef822e7d85beaab79ce2d2Chia-chi Yeh        */
2434842dc6980fb830a4eef822e7d85beaab79ce2d2Chia-chi Yeh        // END android-deleted
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getTopmostVia() == null)
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("No via header in request! ", 0);
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getMethod().equals(Request.NOTIFY)) {
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (getHeader(SubscriptionStateHeader.NAME) == null)
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new ParseException(prefix + SubscriptionStateHeader.NAME, 0);
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (getHeader(EventHeader.NAME) == null)
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new ParseException(prefix + EventHeader.NAME, 0);
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (getMethod().equals(Request.PUBLISH)) {
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /*
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * For determining the type of the published event state, the EPA MUST include a
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * single Event header field in PUBLISH requests. The value of this header field
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * indicates the event package for which this request is publishing event state.
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (getHeader(EventHeader.NAME) == null)
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new ParseException(prefix + EventHeader.NAME, 0);
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * RFC 3261 8.1.1.8 The Contact header field MUST be present and contain exactly one SIP
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * or SIPS URI in any request that can result in the establishment of a dialog. For the
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * methods defined in this specification, that includes only the INVITE request. For these
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * requests, the scope of the Contact is global. That is, the Contact header field value
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * contains the URI at which the UA would like to receive requests, and this URI MUST be
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * valid even if used in subsequent requests outside of any dialogs.
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         *
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * If the Request-URI or top Route header field value contains a SIPS URI, the Contact
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * header field MUST contain a SIPS URI as well.
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine.getMethod().equals(Request.INVITE)
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || requestLine.getMethod().equals(Request.SUBSCRIBE)
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || requestLine.getMethod().equals(Request.REFER)) {
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.getContactHeader() == null) {
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Make sure this is not a target refresh. If this is a target
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // refresh its ok not to have a contact header. Otherwise
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // contact header is mandatory.
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.getToTag() == null)
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw new ParseException(prefix + ContactHeader.NAME, 0);
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (requestLine.getUri() instanceof SipUri) {
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String scheme = ((SipUri) requestLine.getUri()).getScheme();
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if ("sips".equalsIgnoreCase(scheme)) {
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SipUri sipUri = (SipUri) this.getContactHeader().getAddress().getURI();
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (!sipUri.getScheme().equals("sips")) {
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        throw new ParseException("Scheme for contact should be sips:" + sipUri, 0);
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Contact header is mandatory for a SIP INVITE request.
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.getContactHeader() == null
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && (this.getMethod().equals(Request.INVITE)
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        || this.getMethod().equals(Request.REFER) || this.getMethod().equals(
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        Request.SUBSCRIBE))) {
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("Contact Header is Mandatory for a SIP INVITE", 0);
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine != null && requestLine.getMethod() != null
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && getCSeq().getMethod() != null
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && requestLine.getMethod().compareTo(getCSeq().getMethod()) != 0) {
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("CSEQ method mismatch with  Request-Line ", 0);
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the default values in the request URI if necessary.
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setDefaults() {
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // The request line may be unparseable (set to null by the
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // exception handler.
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine == null)
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String method = requestLine.getMethod();
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // The requestLine may be malformed!
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (method == null)
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        GenericURI u = requestLine.getUri();
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (u == null)
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (method.compareTo(Request.REGISTER) == 0 || method.compareTo(Request.INVITE) == 0) {
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (u instanceof SipUri) {
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SipUri sipUri = (SipUri) u;
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipUri.setUserParam(DEFAULT_USER);
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipUri.setTransportParam(DEFAULT_TRANSPORT);
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (ParseException ex) {
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Patch up the request line as necessary.
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setRequestLineDefaults() {
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String method = requestLine.getMethod();
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (method == null) {
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            CSeq cseq = (CSeq) this.getCSeq();
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (cseq != null) {
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                method = getCannonicalName(cseq.getMethod());
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                requestLine.setMethod(method);
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A conveniance function to access the Request URI.
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the requestURI if it exists.
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public javax.sip.address.URI getRequestURI() {
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.requestLine == null)
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return (javax.sip.address.URI) this.requestLine.getUri();
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Sets the RequestURI of Request. The Request-URI is a SIP or SIPS URI or a general URI. It
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * indicates the user or service to which this request is being addressed. SIP elements MAY
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * support Request-URIs with schemes other than "sip" and "sips", for example the "tel" URI
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * scheme. SIP elements MAY translate non-SIP URIs using any mechanism at their disposal,
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * resulting in SIP URI, SIPS URI, or some other scheme.
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param uri the new Request URI of this request message
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setRequestURI(URI uri) {
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( uri == null ) {
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new NullPointerException("Null request URI");
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.requestLine == null) {
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.requestLine = new RequestLine();
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.requestLine.setUri((GenericURI) uri);
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.nullRequest = false;
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the method.
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param method is the method to set.
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IllegalArgumentException if the method is null
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setMethod(String method) {
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (method == null)
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IllegalArgumentException("null method");
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.requestLine == null) {
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.requestLine = new RequestLine();
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Set to standard constants to speed up processing.
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this makes equals compares run much faster in the
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // stack because then it is just identity comparision
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String meth = getCannonicalName(method);
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.requestLine.setMethod(meth);
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.cSeqHeader != null) {
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.cSeqHeader.setMethod(meth);
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (ParseException e) {
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the method from the request line.
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the method from the request line if the method exits and null if the request line
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         or the method does not exist.
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getMethod() {
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine == null)
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return requestLine.getMethod();
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Encode the SIP Request as a string.
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return an encoded String containing the encoded SIP Message.
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String encode() {
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String retval;
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine != null) {
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.setRequestLineDefaults();
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = requestLine.encode() + super.encode();
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (this.isNullRequest()) {
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = "\r\n\r\n";
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = super.encode();
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Encode only the headers and not the content.
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String encodeMessage() {
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String retval;
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine != null) {
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.setRequestLineDefaults();
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = requestLine.encode() + super.encodeSIPHeaders();
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (this.isNullRequest()) {
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = "\r\n\r\n";
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = super.encodeSIPHeaders();
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * ALias for encode above.
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String toString() {
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.encode();
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Make a clone (deep copy) of this object. You can use this if you want to modify a request
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * while preserving the original
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a deep copy of this object.
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Object clone() {
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest retval = (SIPRequest) super.clone();
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Do not copy over the tx pointer -- this is only for internal
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // tracking.
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retval.transactionPointer = null;
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.requestLine != null)
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval.requestLine = (RequestLine) this.requestLine.clone();
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Compare for equality.
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param other object to compare ourselves with.
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean equals(Object other) {
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!this.getClass().equals(other.getClass()))
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest that = (SIPRequest) other;
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return requestLine.equals(that.requestLine) && super.equals(other);
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the message as a linked list of strings. Use this if you want to iterate through the
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * message.
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a linked list containing the request line and headers encoded as strings.
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public LinkedList getMessageAsEncodedStrings() {
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        LinkedList retval = super.getMessageAsEncodedStrings();
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine != null) {
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.setRequestLineDefaults();
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval.addFirst(requestLine.encode());
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Match with a template. You can use this if you want to match incoming messages with a
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * pattern and do something when you find a match. This is useful for building filters/pattern
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * matching responders etc.
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param matchObj object to match ourselves with (null matches wildcard)
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean match(Object matchObj) {
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (matchObj == null)
530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return true;
531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else if (!matchObj.getClass().equals(this.getClass()))
532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else if (matchObj == this)
534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return true;
535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest that = (SIPRequest) matchObj;
536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RequestLine rline = that.requestLine;
537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.requestLine == null && rline != null)
538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else if (this.requestLine == rline)
540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return super.match(matchObj);
541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return requestLine.match(that.requestLine) && super.match(matchObj);
542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get a dialog identifier. Generates a string that can be used as a dialog identifier.
547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param isServer is set to true if this is the UAS and set to false if this is the UAC
549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getDialogId(boolean isServer) {
551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        CallID cid = (CallID) this.getCallId();
552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer retval = new StringBuffer(cid.getCallId());
553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        From from = (From) this.getFrom();
554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        To to = (To) this.getTo();
555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!isServer) {
556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(from.getUserAtHostPort());
557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (from.getTag() != null) {
558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(from.getTag());
560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(to.getUserAtHostPort());
562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (to.getTag() != null) {
563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(to.getTag());
565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(to.getUserAtHostPort());
568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (to.getTag() != null) {
569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(to.getTag());
571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(from.getUserAtHostPort());
573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (from.getTag() != null) {
574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(from.getTag());
576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval.toString().toLowerCase();
579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get a dialog id given the remote tag.
584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getDialogId(boolean isServer, String toTag) {
586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        From from = (From) this.getFrom();
587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        CallID cid = (CallID) this.getCallId();
588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer retval = new StringBuffer(cid.getCallId());
589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!isServer) {
590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(from.getUserAtHostPort());
591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (from.getTag() != null) {
592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(from.getTag());
594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(to.getUserAtHostPort());
596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (toTag != null) {
597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(toTag);
599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(to.getUserAtHostPort());
602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (toTag != null) {
603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(toTag);
605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // retval.append(COLON).append(from.getUserAtHostPort());
607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (from.getTag() != null) {
608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(COLON);
609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval.append(from.getTag());
610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval.toString().toLowerCase();
613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Encode this into a byte array. This is used when the body has been set as a binary array
617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * and you want to encode the body as a byte array for transmission.
618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a byte array containing the SIPRequest encoded as a byte array.
620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public byte[] encodeAsBytes(String transport) {
623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.isNullRequest()) {
624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Encoding a null message for keepalive.
625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return "\r\n\r\n".getBytes();
626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if ( this.requestLine == null ) {
627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return new byte[0];
628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] rlbytes = null;
631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine != null) {
632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                rlbytes = requestLine.encode().getBytes("UTF-8");
634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (UnsupportedEncodingException ex) {
635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                InternalErrorHandler.handleException(ex);
636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] superbytes = super.encodeAsBytes(transport);
639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] retval = new byte[rlbytes.length + superbytes.length];
640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        System.arraycopy(rlbytes, 0, retval, 0, rlbytes.length);
641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        System.arraycopy(superbytes, 0, retval, rlbytes.length, superbytes.length);
642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a default SIPResponse message for this request. Note You must add the necessary
647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * tags to outgoing responses if need be. For efficiency, this method does not clone the
648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * incoming request. If you want to modify the outgoing response, be sure to clone the
649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * incoming request as the headers are shared and any modification to the headers of the
650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * outgoing response will result in a modification of the incoming request. Tag fields are
651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * just copied from the incoming request. Contact headers are removed from the incoming
652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * request. Added by Jeff Keyser.
653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param statusCode Status code for the response. Reason phrase is generated.
655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A SIPResponse with the status and reason supplied, and a copy of all the original
657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         headers from this request.
658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPResponse createResponse(int statusCode) {
661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String reasonPhrase = SIPResponse.getReasonPhrase(statusCode);
663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.createResponse(statusCode, reasonPhrase);
664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a default SIPResponse message for this request. Note You must add the necessary
669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * tags to outgoing responses if need be. For efficiency, this method does not clone the
670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * incoming request. If you want to modify the outgoing response, be sure to clone the
671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * incoming request as the headers are shared and any modification to the headers of the
672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * outgoing response will result in a modification of the incoming request. Tag fields are
673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * just copied from the incoming request. Contact headers are removed from the incoming
674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * request. Added by Jeff Keyser. Route headers are not added to the response.
675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param statusCode Status code for the response.
677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param reasonPhrase Reason phrase for this response.
678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A SIPResponse with the status and reason supplied, and a copy of all the original
680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         headers from this request except the ones that are not supposed to be part of the
681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         response .
682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPResponse createResponse(int statusCode, String reasonPhrase) {
685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPResponse newResponse;
686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator headerIterator;
687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPHeader nextHeader;
688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newResponse = new SIPResponse();
690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newResponse.setStatusCode(statusCode);
692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException ex) {
693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IllegalArgumentException("Bad code " + statusCode);
694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (reasonPhrase != null)
696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newResponse.setReasonPhrase(reasonPhrase);
697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newResponse.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode));
699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        headerIterator = getHeaders();
700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (headerIterator.hasNext()) {
701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            nextHeader = (SIPHeader) headerIterator.next();
702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (nextHeader instanceof From
703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || nextHeader instanceof To
704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || nextHeader instanceof ViaList
705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || nextHeader instanceof CallID
706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || (nextHeader instanceof RecordRouteList && mustCopyRR(statusCode))
707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || nextHeader instanceof CSeq
708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // We just copy TimeStamp for all headers (not just 100).
709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || nextHeader instanceof TimeStamp) {
710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    newResponse.attachHeader((SIPHeader) nextHeader.clone(), false);
714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (SIPDuplicateHeaderException e) {
715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    e.printStackTrace();
716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (MessageFactoryImpl.getDefaultServerHeader() != null) {
720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newResponse.setHeader(MessageFactoryImpl.getDefaultServerHeader());
721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (newResponse.getStatusCode() == 100) {
724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Trying is never supposed to have the tag parameter set.
725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newResponse.getTo().removeParameter("tag");
726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ServerHeader server = MessageFactoryImpl.getDefaultServerHeader();
729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (server != null) {
730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newResponse.setHeader(server);
731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return newResponse;
733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Helper method for createResponse, to avoid copying Record-Route unless needed
736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private final boolean mustCopyRR( int code ) {
737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	// Only for 1xx-2xx, not for 100 or errors
738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	if ( code>100 && code<300 ) {
739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    		return isDialogCreating( this.getMethod() ) && getToTag() == null;
740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	} else return false;
741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a default SIPResquest message that would cancel this request. Note that tag
745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * assignment and removal of is left to the caller (we use whatever tags are present in the
746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * original request).
747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A CANCEL SIPRequest constructed according to RFC3261 section 9.1
749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws SipException
751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws ParseException
752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPRequest createCancelRequest() throws SipException {
754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // see RFC3261 9.1
756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // A CANCEL request SHOULD NOT be sent to cancel a request other than
758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // INVITE
759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (!this.getMethod().equals(Request.INVITE))
761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new SipException("Attempt to create CANCEL for " + this.getMethod());
762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * The following procedures are used to construct a CANCEL request. The Request-URI,
765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Call-ID, To, the numeric part of CSeq, and From header fields in the CANCEL request
766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * MUST be identical to those in the request being cancelled, including tags. A CANCEL
767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * constructed by a client MUST have only a single Via header field value matching the top
768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Via value in the request being cancelled. Using the same values for these header fields
769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * allows the CANCEL to be matched with the request it cancels (Section 9.2 indicates how
770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * such matching occurs). However, the method part of the CSeq header field MUST have a
771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * value of CANCEL. This allows it to be identified and processed as a transaction in its
772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * own right (See Section 17).
773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest cancel = new SIPRequest();
775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setRequestLine((RequestLine) this.requestLine.clone());
776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setMethod(Request.CANCEL);
777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setHeader((Header) this.callIdHeader.clone());
778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setHeader((Header) this.toHeader.clone());
779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setHeader((Header) cSeqHeader.clone());
780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            cancel.getCSeq().setMethod(Request.CANCEL);
782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (ParseException e) {
783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            e.printStackTrace(); // should not happen
784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setHeader((Header) this.fromHeader.clone());
786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.addFirst((Header) this.getTopmostVia().clone());
788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        cancel.setHeader((Header) this.maxForwardsHeader.clone());
789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * If the request being cancelled contains a Route header field, the CANCEL request MUST
792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * include that Route header field's values.
793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.getRouteHeaders() != null) {
795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            cancel.setHeader((SIPHeaderList< ? >) this.getRouteHeaders().clone());
796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            cancel.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return cancel;
802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a default ACK SIPRequest message for this original request. Note that the
806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * defaultACK SIPRequest does not include the content of the original SIPRequest. If
807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * responseToHeader is null then the toHeader of this request is used to construct the ACK.
808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Note that tag fields are just copied from the original SIP Request. Added by Jeff Keyser.
809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param responseToHeader To header to use for this request.
811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A SIPRequest with an ACK method.
813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPRequest createAckRequest(To responseToHeader) {
815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest newRequest;
816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator headerIterator;
817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPHeader nextHeader;
818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest = new SIPRequest();
820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setRequestLine((RequestLine) this.requestLine.clone());
821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setMethod(Request.ACK);
822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        headerIterator = getHeaders();
823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (headerIterator.hasNext()) {
824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            nextHeader = (SIPHeader) headerIterator.next();
825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (nextHeader instanceof RouteList) {
826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Ack and cancel do not get ROUTE headers.
827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Route header for ACK is assigned by the
828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Dialog if necessary.
829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                continue;
830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ProxyAuthorization) {
831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Remove proxy auth header.
832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Assigned by the Dialog if necessary.
833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                continue;
834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ContentLength) {
835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Adding content is responsibility of user.
836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = (SIPHeader) nextHeader.clone();
837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((ContentLength) nextHeader).setContentLength(0);
839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (InvalidArgumentException e) {
840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ContentType) {
842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Content type header is removed since
843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // content length is 0.
844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                continue;
845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof CSeq) {
846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // The CSeq header field in the
847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // ACK MUST contain the same value for the
848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // sequence number as was present in the
849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // original request, but the method parameter
850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // MUST be equal to "ACK".
851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                CSeq cseq = (CSeq) nextHeader.clone();
852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    cseq.setMethod(Request.ACK);
854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (ParseException e) {
855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = cseq;
857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof To) {
858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (responseToHeader != null) {
859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextHeader = responseToHeader;
860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextHeader = (SIPHeader) nextHeader.clone();
862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ContactList || nextHeader instanceof Expires) {
864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // CONTACT header does not apply for ACK requests.
865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                continue;
866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ViaList) {
867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Bug reported by Gianluca Martinello
868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // The ACK MUST contain a single Via header field,
869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // and this MUST be equal to the top Via header
870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // field of the original
871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // request.
872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = (SIPHeader) ((ViaList) nextHeader).getFirst().clone();
874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = (SIPHeader) nextHeader.clone();
876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                newRequest.attachHeader(nextHeader, false);
880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (SIPDuplicateHeaderException e) {
881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                e.printStackTrace();
882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return newRequest;
889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates an ACK for non-2xx responses according to RFC3261 17.1.1.3
893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A SIPRequest with an ACK method.
895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws SipException
896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws NullPointerException
897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws ParseException
898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @author jvb
900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public final SIPRequest createErrorAck(To responseToHeader) throws SipException,
902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ParseException {
903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * The ACK request constructed by the client transaction MUST contain values for the
906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Call-ID, From, and Request-URI that are equal to the values of those header fields in
907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * the request passed to the transport by the client transaction (call this the "original
908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * request"). The To header field in the ACK MUST equal the To header field in the
909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * response being acknowledged, and therefore will usually differ from the To header field
910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * in the original request by the addition of the tag parameter. The ACK MUST contain a
911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * single Via header field, and this MUST be equal to the top Via header field of the
912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * original request. The CSeq header field in the ACK MUST contain the same value for the
913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * sequence number as was present in the original request, but the method parameter MUST
914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * be equal to "ACK".
915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest newRequest = new SIPRequest();
917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setRequestLine((RequestLine) this.requestLine.clone());
918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setMethod(Request.ACK);
919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setHeader((Header) this.callIdHeader.clone());
920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setHeader((Header) this.maxForwardsHeader.clone()); // ISSUE
921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // 130
922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // fix
923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setHeader((Header) this.fromHeader.clone());
924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setHeader((Header) responseToHeader.clone());
925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.addFirst((Header) this.getTopmostVia().clone());
926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.setHeader((Header) cSeqHeader.clone());
927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.getCSeq().setMethod(Request.ACK);
928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * If the INVITE request whose response is being acknowledged had Route header fields,
931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * those header fields MUST appear in the ACK. This is to ensure that the ACK can be
932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * routed properly through any downstream stateless proxies.
933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.getRouteHeaders() != null) {
935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newRequest.setHeader((SIPHeaderList) this.getRouteHeaders().clone());
936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return newRequest;
942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create a new default SIPRequest from the original request. Warning: the newly created
946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * SIPRequest, shares the headers of this request but we generate any new headers that we need
947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * to modify so the original request is umodified. However, if you modify the shared headers
948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * after this request is created, then the newly created request will also be modified. If you
949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * want to modify the original request without affecting the returned Request make sure you
950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * clone it before calling this method.
951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Only required headers are copied.
953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <ul>
954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <li> Contact headers are not included in the newly created request. Setting the appropriate
955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * sequence number is the responsibility of the caller. </li>
956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <li> RouteList is not copied for ACK and CANCEL </li>
957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <li> Note that we DO NOT copy the body of the argument into the returned header. We do not
958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * copy the content type header from the original request either. These have to be added
959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * seperately and the content length has to be correctly set if necessary the content length
960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * is set to 0 in the returned header. </li>
961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <li>Contact List is not copied from the original request.</li>
962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <li>RecordRoute List is not included from original request. </li>
963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * <li>Via header is not included from the original request. </li>
964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * </ul>
965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param requestLine is the new request line.
967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param switchHeaders is a boolean flag that causes to and from headers to switch (set this
969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        to true if you are the server of the transaction and are generating a BYE request).
970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        If the headers are switched, we generate new From and To headers otherwise we just
971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        use the incoming headers.
972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a new Default SIP Request which has the requestLine specified.
974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPRequest createSIPRequest(RequestLine requestLine, boolean switchHeaders) {
977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest newRequest = new SIPRequest();
978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newRequest.requestLine = requestLine;
979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator<SIPHeader> headerIterator = this.getHeaders();
980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (headerIterator.hasNext()) {
981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPHeader nextHeader = (SIPHeader) headerIterator.next();
982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // For BYE and cancel set the CSeq header to the
983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // appropriate method.
984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (nextHeader instanceof CSeq) {
985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                CSeq newCseq = (CSeq) nextHeader.clone();
986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = newCseq;
987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    newCseq.setMethod(requestLine.getMethod());
989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (ParseException e) {
990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ViaList) {
992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Via via = (Via) (((ViaList) nextHeader).getFirst().clone());
993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                via.removeParameter("branch");
994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = via;
995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Cancel and ACK preserve the branch ID.
996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof To) {
997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                To to = (To) nextHeader;
998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (switchHeaders) {
999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextHeader = new From(to);
1000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((From) nextHeader).removeTag();
1001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
1002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextHeader = (SIPHeader) to.clone();
1003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((To) nextHeader).removeTag();
1004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof From) {
1006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                From from = (From) nextHeader;
1007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (switchHeaders) {
1008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextHeader = new To(from);
1009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((To) nextHeader).removeTag();
1010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
1011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextHeader = (SIPHeader) from.clone();
1012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    ((From) nextHeader).removeTag();
1013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (nextHeader instanceof ContentLength) {
1015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ContentLength cl = (ContentLength) nextHeader.clone();
1016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
1017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    cl.setContentLength(0);
1018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (InvalidArgumentException e) {
1019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextHeader = cl;
1021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (!(nextHeader instanceof CallID) && !(nextHeader instanceof MaxForwards)) {
1022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Route is kept by dialog.
1023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // RR is added by the caller.
1024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Contact is added by the Caller
1025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Any extension headers must be added
1026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // by the caller.
1027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                continue;
1028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
1030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                newRequest.attachHeader(nextHeader, false);
1031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (SIPDuplicateHeaderException e) {
1032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                e.printStackTrace();
1033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
1036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
1037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return newRequest;
1040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create a BYE request from this request.
1045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param switchHeaders is a boolean flag that causes from and isServerTransaction to headers
1047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        to be swapped. Set this to true if you are the server of the dialog and are
1048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *        generating a BYE request for the dialog.
1049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a new default BYE request.
1050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPRequest createBYERequest(boolean switchHeaders) {
1052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RequestLine requestLine = (RequestLine) this.requestLine.clone();
1053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        requestLine.setMethod("BYE");
1054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.createSIPRequest(requestLine, switchHeaders);
1055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create an ACK request from this request. This is suitable for generating an ACK for an
1059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * INVITE client transaction.
1060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return an ACK request that is generated from this request.
1062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPRequest createACKRequest() {
1064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        RequestLine requestLine = (RequestLine) this.requestLine.clone();
1065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        requestLine.setMethod(Request.ACK);
1066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.createSIPRequest(requestLine, false);
1067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the host from the topmost via header.
1071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the string representation of the host from the topmost via header.
1073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getViaHost() {
1075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Via via = (Via) this.getViaHeaders().getFirst();
1076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return via.getHost();
1077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the port from the topmost via header.
1082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the port from the topmost via header (5060 if there is no port indicated).
1084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getViaPort() {
1086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Via via = (Via) this.getViaHeaders().getFirst();
1087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (via.hasPort())
1088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return via.getPort();
1089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
1090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return 5060;
1091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the first line encoded.
1095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return a string containing the encoded request line.
1097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getFirstLine() {
1099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (requestLine == null)
1100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
1102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return this.requestLine.encode();
1103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the sip version.
1107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipVersion the sip version to set.
1109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setSIPVersion(String sipVersion) throws ParseException {
1111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipVersion == null || !sipVersion.equalsIgnoreCase("SIP/2.0"))
1112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new ParseException("sipVersion", 0);
1113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.requestLine.setSipVersion(sipVersion);
1114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the SIP version.
1118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the SIP version from the request line.
1120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getSIPVersion() {
1122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.requestLine.getSipVersion();
1123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Book keeping method to return the current tx for the request if one exists.
1127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the assigned tx.
1129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Object getTransaction() {
1131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Return an opaque pointer to the transaction object.
1132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This is for consistency checking and quick lookup.
1133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.transactionPointer;
1134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Book keeping field to set the current tx for the request.
1138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transaction
1140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setTransaction(Object transaction) {
1142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.transactionPointer = transaction;
1143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Book keeping method to get the messasge channel for the request.
1147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the message channel for the request.
1149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Object getMessageChannel() {
1152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // return opaque ptr to the message chanel on
1153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // which the message was recieved. For consistency
1154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // checking and lookup.
1155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.messageChannel;
1156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the message channel for the request ( bookkeeping field ).
1160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageChannel
1162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setMessageChannel(Object messageChannel) {
1165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.messageChannel = messageChannel;
1166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Generates an Id for checking potentially merged requests.
1170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return String to check for merged requests
1172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getMergeId() {
1174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
1175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * generate an identifier from the From tag, Call-ID, and CSeq
1176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
1177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String fromTag = this.getFromTag();
1178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String cseq = this.cSeqHeader.toString();
1179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String callId = this.callIdHeader.getCallId();
1180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /* NOTE : The RFC does NOT specify you need to include a Request URI
1181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * This is added here for the case of Back to Back User Agents.
1182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
1183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String requestUri = this.getRequestURI().toString();
1184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (fromTag != null) {
1186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return new StringBuffer().append(requestUri).append(":").append(fromTag).append(":").append(cseq).append(":")
1187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    .append(callId).toString();
1188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else
1189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param inviteTransaction the inviteTransaction to set
1195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setInviteTransaction(Object inviteTransaction) {
1197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.inviteTransaction = inviteTransaction;
1198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the inviteTransaction
1202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Object getInviteTransaction() {
1204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return inviteTransaction;
1205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
1212