FileDocCategorySizeDatePackage
Response.javaAPI DocphoneME MR2 API (J2ME)38527Wed May 02 18:00:42 BST 2007gov.nist.siplite.message

Response.java

/*
 * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
 * Reserved.  Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
/*
 */
package gov.nist.siplite.message;

import java.util.Enumeration;
import java.io.UnsupportedEncodingException;
import javax.microedition.sip.SipException;

import gov.nist.siplite.address.*;
import gov.nist.core.*;
import gov.nist.siplite.header.*;

/**
 * SIP Response structure.
 *
 * @version JAIN-SIP-1.1
 *
 *
 *<a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
 *
 */
public final class Response extends Message {
    /** The current status line. */
    protected StatusLine statusLine;

    /**
     * This response indicates that the request has been received by the
     * next-hop server and that some unspecified action is being taken on
     * behalf of this call (for example, a database is being consulted). This
     * response, like all other provisional responses, stops retransmissions of
     * an INVITE by a UAC. The 100 (Trying) response is different from other
     * provisional responses, in that it is never forwarded upstream by a
     * stateful proxy.
     */
    public static final int TRYING = 100;

    /**
     * The User Agent receiving the INVITE is trying to alert the user. This
     * response MAY be used to initiate local ringback.
     */
    public static final int RINGING = 180;

    /**
     * A server MAY use this status code to indicate that the call is being
     * forwarded to a different set of destinations.
     */
    public static final int CALL_IS_BEING_FORWARDED = 181;

    /**
     * The called party is temporarily unavailable, but the server has decided
     * to queue the call rather than reject it. When the callee becomes
     * available, it will return the appropriate final status response. The
     * reason phrase MAY give further details about the status of the call,
     * for example, "5 calls queued; expected waiting time is 15 minutes". The
     * server MAY issue several 182 (Queued) responses to update the caller
     * about the status of the queued call.
     */
    public static final int QUEUED = 182;

    /**
     * The 183 (Session Progress) response is used to convey information about
     * the progress of the call that is not otherwise classified. The
     * Reason-Phrase, header fields, or message body MAY be used to convey more
     * details about the call progress.
     *
     * @since v1.1
     */
    public static final int SESSION_PROGRESS = 183;

    /**
     * The request has succeeded. The information returned with the response
     * depends on the method used in the request.
     */
    public static final int OK = 200;

    /**
     * The Acceptable extension response code signifies that the request has
     * been accepted for processing, but the processing has not been completed.
     * The request might or might not eventually be acted upon, as it might be
     * disallowed when processing actually takes place. There is no facility
     * for re-sending a status code from an asynchronous operation such as this.
     * The 202 response is intentionally non-committal. Its purpose is to allow
     * a server to accept a request for some other process (perhaps a
     * batch-oriented process that is only run once per day) without requiring
     * that the user agent's connection to the server persist until the process
     * is completed. The entity returned with this response SHOULD include an
     * indication of the request's current status and either a pointer to a
     * status monitor or some estimate of when the user can expect the request
     * to be fulfilled. This response code is specific to the event
     * notification framework.
     *
     * @since v1.1
     */
    public static final int ACCEPTED = 202;

    /**
     * The address in the request resolved to several choices, each with its
     * own specific location, and the user (or UA) can select a preferred
     * communication end point and redirect its request to that location.
     * <p>
     * The response MAY include a message body containing a list of resource
     * characteristics and location(s) from which the user or UA can choose
     * the one most appropriate, if allowed by the Accept request header field.
     * However, no MIME types have been defined for this message body.
     * <p>
     * The choices SHOULD also be listed as Contact fields. Unlike HTTP, the
     * SIP response MAY contain several Contact fields or a list of addresses
     * in a Contact field. User Agents MAY use the Contact header field value
     * for automatic redirection or MAY ask the user to confirm a choice.
     * However, this specification does not define any standard for such
     * automatic selection.
     * <p>
     * This status response is appropriate if the callee can be reached at
     * several different locations and the server cannot or prefers not to
     * proxy the request.
     */
    public static final int MULTIPLE_CHOICES = 300;

    /**
     * The user can no longer be found at the address in the Request-URI, and
     * the requesting client SHOULD retry at the new address given by the
     * Contact header field. The requestor SHOULD update any local directories,
     * address books, and user location caches with this new value and redirect
     * future requests to the address(es) listed.
     */
    public static final int MOVED_PERMANENTLY = 301;

    /**
     * The requesting client SHOULD retry the request at the new address(es)
     * given by the Contact header field. The Request-URI of the new request
     * uses the value of the Contact header field in the response.
     * <p>
     * The duration of the validity of the Contact URI can be indicated through
     * an Expires header field or an expires parameter in the Contact header
     * field. Both proxies and User Agents MAY cache this URI for the duration
     * of the expiration time. If there is no explicit expiration time, the
     * address is only valid once for recursing, and MUST NOT be cached for
     * future transactions.
     * <p>
     * If the URI cached from the Contact header field fails, the Request-URI
     * from the redirected request MAY be tried again a single time. The
     * temporary URI may have become out-of-date sooner than the expiration
     * time, and a new temporary URI may be available.
     */
    public static final int MOVED_TEMPORARILY = 302;

    /**
     * The requested resource MUST be accessed through the proxy given by the
     * Contact field. The Contact field gives the URI of the proxy. The
     * recipient is expected to repeat this single request via the proxy.
     * 305 (Use Proxy) responses MUST only be generated by UASs.
     */
    public static final int USE_PROXY = 305;

    /**
     * The call was not successful, but alternative services are possible. The
     * alternative services are described in the message body of the response.
     * Formats for such bodies are not defined here, and may be the subject of
     * future standardization.
     */
    public static final int ALTERNATIVE_SERVICE = 380;

    /**
     * The request could not be understood due to malformed syntax. The
     * Reason-Phrase SHOULD identify the syntax problem in more detail, for
     * example, "Missing Call-ID header field".
     */
    public static final int BAD_REQUEST = 400;

    /**
     * The request requires user authentication. This response is issued by
     * UASs and registrars, while 407 (Proxy Authentication Required) is used
     * by proxy servers.
     */
    public static final int UNAUTHORIZED = 401;

    /**
     * Reserved for future use.
     */
    public static final int PAYMENT_REQUIRED = 402;

    /**
     * The server understood the request, but is refusing to fulfill it.
     * Authorization will not help, and the request SHOULD NOT be repeated.
     */
    public static final int FORBIDDEN = 403;

    /**
     * The server has definitive information that the user does not exist at
     * the domain specified in the Request-URI. This status is also returned
     * if the domain in the Request-URI does not match any of the domains
     * handled by the recipient of the request.
     */
    public static final int NOT_FOUND = 404;

    /**
     * The method specified in the Request-Line is understood, but not allowed
     * for the address identified by the Request-URI. The response MUST include
     * an Allow header field containing a list of valid methods for the
     * indicated address
     */
    public static final int METHOD_NOT_ALLOWED = 405;

    /**
     * The resource identified by the request is only capable of generating
     * response entities that have content characteristics not acceptable
     * according to the Accept header field sent in the request.
     */
    public static final int NOT_ACCEPTABLE = 406;

    /**
     * This code is similar to 401 (Unauthorized), but indicates that
     * the client
     * MUST first authenticate itself with the proxy. This status code can be
     * used for applications where access to the communication channel (for
     * example, a telephony gateway) rather than the callee requires
     * authentication.
     */
    public static final int PROXY_AUTHENTICATION_REQUIRED = 407;

    /**
     * The server could not produce a response within a suitable amount of
     * time, for example, if it could not determine the location of the user
     * in time. The client MAY repeat the request without modifications at
     * any later time.
     */
    public static final int REQUEST_TIMEOUT = 408;

    /**
     * The requested resource is no longer available at the server and no
     * forwarding address is known. This condition is expected to be considered
     * permanent. If the server does not know, or has no facility to determine,
     * whether or not the condition is permanent, the status code 404
     * (Not Found) SHOULD be used instead.
     */
    public static final int GONE = 410;

    /**
     * The server is refusing to process a request because the request
     * entity-body is larger than the server is willing or able to process. The
     * server MAY close the connection to prevent the client from continuing
     * the request. If the condition is temporary, the server SHOULD include a
     * Retry-After header field to indicate that it is temporary and after what
     * time the client MAY try again.
     *
     * @since v1.1
     */
    public static final int REQUEST_ENTITY_TOO_LARGE = 413;

    /**
     * The server is refusing to service the request because the Request-URI
     * is longer than the server is willing to interpret.
     *
     * @since v1.1
     */
    public static final int REQUEST_URI_TOO_LONG = 414;

    /**
     * The server is refusing to service the request because the message body
     * of the request is in a format not supported by the server for the
     * requested method. The server MUST return a list of acceptable formats
     * using the Accept, Accept-Encoding, or Accept-Language header field,
     * depending on the specific problem with the content.
     */
    public static final int UNSUPPORTED_MEDIA_TYPE = 415;

    /**
     * The server cannot process the request because the scheme of the URI in
     * the Request-URI is unknown to the server.
     *
     * @since v1.1
     */
    public static final int UNSUPPORTED_URI_SCHEME = 416;

    /**
     * The server did not understand the protocol extension specified in a
     * Proxy-Require or Require header field. The server MUST include a list of
     * the unsupported extensions in an Unsupported header field in
     * the response.
     */
    public static final int BAD_EXTENSION = 420;

    /**
     * The UAS needs a particular extension to process the request, but this
     * extension is not listed in a Supported header field in the request.
     * Responses with this status code MUST contain a Require header field
     * listing the required extensions.
     * <p>
     * A UAS SHOULD NOT use this response unless it truly cannot provide any
     * useful service to the client. Instead, if a desirable extension is not
     * listed in the Supported header field, servers SHOULD process the request
     * using baseline SIP capabilities and any extensions supported by the
     * client.
     *
     * @since v1.1
     */
    public static final int EXTENSION_REQUIRED = 421;

    /**
     * The server is rejecting the request because the expiration time of the
     * resource refreshed by the request is too short. This response can be
     * used by a registrar to reject a registration whose Contact header field
     * expiration time was too small.
     *
     * @since v1.1
     */
    public static final int INTERVAL_TOO_BRIEF = 423;

    /**
     * The callee's end system was contacted successfully but the callee is
     * currently unavailable (for example, is not logged in, logged in but in a
     * state that precludes communication with the callee, or has activated the
     * "do not disturb" feature). The response MAY indicate a better time to
     * call in the Retry-After header field. The user could also be available
     * elsewhere (unbeknownst to this server). The reason phrase
     * SHOULD indicate
     * a more precise cause as to why the callee is unavailable. This value
     * SHOULD be settable by the UA. Status 486 (Busy Here) MAY be used to more
     * precisely indicate a particular reason for the call failure.
     * <p>
     * This status is also returned by a redirect or proxy server that
     * recognizes the user identified by the Request-URI, but does not
     * currently have a valid forwarding location for that user.
     *
     * @since v1.1
     */
    public static final int TEMPORARILY_UNAVAILABLE = 480;

    /**
     * This status indicates that the UAS received a request that does not
     * match any existing dialog or transaction.
     */
    public static final int CALL_OR_TRANSACTION_DOES_NOT_EXIST = 481;

    /**
     * The server has detected a loop.
     */
    public static final int LOOP_DETECTED = 482;

    /**
     * The server received a request that contains a Max-Forwards header field
     * with the value zero.
     */
    public static final int TOO_MANY_HOPS = 483;

    /**
     * The server received a request with a Request-URI that was incomplete.
     * Additional information SHOULD be provided in the reason phrase. This
     * status code allows overlapped dialing. With overlapped dialing, the
     * client does not know the length of the dialing string. It sends strings
     * of increasing lengths, prompting the user for more input, until it no
     * longer receives a 484 (Address Incomplete) status response.
     */
    public static final int ADDRESS_INCOMPLETE = 484;

    /**
     * The Request-URI was ambiguous. The response MAY contain a listing of
     * possible unambiguous addresses in Contact header fields. Revealing
     * alternatives can infringe on privacy of the user or the organization.
     * It MUST be possible to configure a server to respond with status 404
     * (Not Found) or to suppress the listing of possible choices for ambiguous
     * Request-URIs. Some email and voice mail systems provide this
     * functionality. A status code separate from 3xx is used since the
     * semantics are different: for 300, it is assumed that the same person or
     * service will be reached by the choices provided. While an automated
     * choice or sequential search makes sense for a 3xx response, user
     * intervention is required for a 485 (Ambiguous) response.
     */
    public static final int AMBIGUOUS = 485;

    /**
     * The callee's end system was contacted successfully, but the callee is
     * currently not willing or able to take additional calls at this end
     * system. The response MAY indicate a better time to call in the
     * Retry-After
     * header field. The user could also be available elsewhere, such as
     * through a voice mail service. Status 600 (Busy Everywhere) SHOULD be
     * used if the client knows that no other end system will be able to accept
     * this call.
     */
    public static final int BUSY_HERE = 486;

    /**
     * The request was terminated by a BYE or CANCEL request. This response is
     * never returned for a CANCEL request itself.
     *
     * @since v1.1
     */
    public static final int REQUEST_TERMINATED = 487;

    /**
     * The response has the same meaning as 606 (Not Acceptable), but only
     * applies to the specific resource addressed by the Request-URI and the
     * request may succeed elsewhere. A message body containing a description
     * of media capabilities MAY be present in the response, which is formatted
     * according to the Accept header field in the INVITE (or application/sdp
     * if not present), the same as a message body in a 200 (OK) response to
     * an OPTIONS request.
     *
     * @since v1.1
     */
    public static final int NOT_ACCEPTABLE_HERE = 488;

    /**
     * The Bad Event extension response code is used to indicate that the
     * server did not understand the event package specified in a "Event"
     * header field. This response code is specific to the event notification
     * framework.
     *
     * @since v1.1
     */
    public static final int BAD_EVENT = 489;

    /**
     * The request was received by a UAS that had a pending request within
     * the same dialog.
     *
     * @since v1.1
     */
    public static final int REQUEST_PENDING = 491;

    /**
     * The request was received by a UAS that contained an encrypted MIME body
     * for which the recipient does not possess or will not provide an
     * appropriate decryption key. This response MAY have a single body
     * containing an appropriate public key that should be used to encrypt MIME
     * bodies sent to this UA.
     *
     * @since v1.1
     */
    public static final int UNDECIPHERABLE = 493;

    /**
     * The server encountered an unexpected condition that prevented it from
     * fulfilling the request. The client MAY display the specific error
     * condition and MAY retry the request after several seconds. If the
     * condition is temporary, the server MAY indicate when the client may
     * retry the request using the Retry-After header field.
     */
    public static final int SERVER_INTERNAL_ERROR = 500;

    /**
     * The server does not support the functionality required to fulfill the
     * request. This is the appropriate response when a UAS does not recognize
     * the request method and is not capable of supporting it for any user.
     * Proxies forward all requests regardless of method. Note that a 405
     * (Method Not Allowed) is sent when the server recognizes the request
     * method, but that method is not allowed or supported.
     */
    public static final int NOT_IMPLEMENTED = 501;

    /**
     * The server, while acting as a gateway or proxy, received an invalid
     * response from the downstream server it accessed in attempting to
     * fulfill the request.
     */
    public static final int BAD_GATEWAY = 502;

    /**
     * The server is temporarily unable to process the request due to a
     * temporary overloading or maintenance of the server. The server MAY
     * indicate when the client should retry the request in a Retry-After
     * header field. If no Retry-After is given, the client MUST act as if it
     * had received a 500 (Server Internal Error) response.
     * <p>
     * A client (proxy or UAC) receiving a 503 (Service Unavailable) SHOULD
     * attempt to forward the request to an alternate server. It SHOULD NOT
     * forward any other requests to that server for the duration specified
     * in the Retry-After header field, if present.
     * <p>
     * Servers MAY refuse the connection or drop the request instead of
     * responding with 503 (Service Unavailable).
     *
     * @since v1.1
     */
    public static final int SERVICE_UNAVAILABLE = 503;

    /**
     * The server did not receive a timely response from an external server
     * it accessed in attempting to process the request. 408 (Request Timeout)
     * should be used instead if there was no response within the
     * period specified in the Expires header field from the upstream server.
     */
    public static final int SERVER_TIMEOUT = 504;

    /**
     * The server does not support, or refuses to support, the SIP protocol
     * version that was used in the request. The server is indicating that
     * it is unable or unwilling to complete the request using the same major
     * version as the client, other than with this error message.
     */
    public static final int VERSION_NOT_SUPPORTED = 505;

    /**
     * The server was unable to process the request since the message length
     * exceeded its capabilities.
     *
     * @since v1.1
     */
    public static final int MESSAGE_TOO_LARGE = 513;

    /**
     * The callee's end system was contacted successfully but the callee is
     * busy and does not wish to take the call at this time. The response
     * MAY indicate a better time to call in the Retry-After header field.
     * If the callee does not wish to reveal the reason for declining the call,
     * the callee uses status code 603 (Decline) instead. This status response
     * is returned only if the client knows that no other end point (such as a
     * voice mail system) will answer the request. Otherwise, 486 (Busy Here)
     * should be returned.
     */
    public static final int BUSY_EVERYWHERE = 600;

    /**
     * The callee's machine was successfully contacted but the user explicitly
     * does not wish to or cannot participate. The response MAY indicate a
     * better time to call in the Retry-After header field. This status
     * response is returned only if the client knows that no other end point
     * will answer the request.
     */
    public static final int DECLINE = 603;

    /**
     * The server has authoritative information that the user indicated in the
     * Request-URI does not exist anywhere.
     */
    public static final int DOES_NOT_EXIST_ANYWHERE = 604;

    /**
     * The user's agent was contacted successfully but some aspects of the
     * session description such as the requested media, bandwidth, or
     * addressing
     * style were not acceptable. A 606 (Not Acceptable) response means that
     * the user wishes to communicate, but cannot adequately support the
     * session described. The 606 (Not Acceptable) response MAY contain a list
     * of reasons in a Warning header field describing why the session
     * described
     * cannot be supported.
     * <p>
     * A message body containing a description of media capabilities MAY be
     * present in the response, which is formatted according to the Accept
     * header field in the INVITE (or application/sdp if not present), the same
     * as a message body in a 200 (OK) response to an OPTIONS request.
     * <p>
     * It is hoped that negotiation will not frequently be needed, and when a
     * new user is being invited to join an already existing conference,
     * negotiation may not be possible. It is up to the invitation initiator to
     * decide whether or not to act on a 606 (Not Acceptable) response.
     * <p>
     * This status response is returned only if the client knows that no other
     * end point will answer the request. This specification renames this
     * status code from NOT_ACCEPTABLE as in RFC3261 to SESSION_NOT_ACCEPTABLE
     * due to it conflict with 406 (Not Acceptable) defined in this interface.
     */
    public static final int SESSION_NOT_ACCEPTABLE = 606;

    /**
     * Gets the reason phrase.
     * @param rc the reason code
     * @return the reason phrase as a string
     */
    public static String getReasonPhrase(int rc) {
        String retval = null;

        switch (rc) {
            case TRYING:
                retval = "Trying";
                break;

            case RINGING:
                retval = "Ringing";
                break;

            case CALL_IS_BEING_FORWARDED:
                retval = "Call is being forwarded";
                break;

            case QUEUED:
                retval = "Queued";
                break;

            case SESSION_PROGRESS:
                retval = "Session progress";
                break;

            case OK:
                retval = "OK";
                break;

            case ACCEPTED :
                retval = "Accepted";
                break;

            case MULTIPLE_CHOICES :
                retval = "Multiple choices";
                break;

            case MOVED_PERMANENTLY:
                retval = "Moved permanently";
                break;

            case MOVED_TEMPORARILY :
                retval = "Moved Temporarily";
                break;

            case USE_PROXY :
                retval = "Use proxy";
                break;

            case ALTERNATIVE_SERVICE :
                retval = "Alternative service";
                break;

            case BAD_REQUEST:
                retval = "Bad request";
                break;

            case UNAUTHORIZED :
                retval = "Unauthorized";
                break;

            case PAYMENT_REQUIRED :
                retval = "Payment required";
                break;

            case FORBIDDEN :
                retval = "Forbidden";
                break;

            case NOT_FOUND :
                retval = "Not found";
                break;

            case METHOD_NOT_ALLOWED :
                retval = "Method not allowed";
                break;

            case NOT_ACCEPTABLE:
                retval = "Not acceptable";
                break;

            case PROXY_AUTHENTICATION_REQUIRED :
                retval = "Proxy Authentication required";
                break;

            case REQUEST_TIMEOUT :
                retval = "Request timeout";
                break;

            case GONE :
                retval = "Gone";
                break;

            case TEMPORARILY_UNAVAILABLE :
                retval = "Temporarily Unavailable";
                break;

            case REQUEST_ENTITY_TOO_LARGE :
                retval = "Request entity too large";
                break;

            case REQUEST_URI_TOO_LONG :
                retval = "Request-URI too large";
                break;

            case UNSUPPORTED_MEDIA_TYPE:
                retval = "Unsupported media type";
                break;

            case UNSUPPORTED_URI_SCHEME:
                retval = "Unsupported URI Scheme";
                break;

            case BAD_EXTENSION :
                retval = "Bad extension";
                break;

            case EXTENSION_REQUIRED :
                retval = "Etension Required";
                break;

            case INTERVAL_TOO_BRIEF :
                retval = "Interval too brief";
                break;

            case CALL_OR_TRANSACTION_DOES_NOT_EXIST :
                retval = "Call leg/Transaction does not exist";
                break;

            case LOOP_DETECTED:
                retval = "Loop detected";
                break;

            case TOO_MANY_HOPS :
                retval = "Too many hops";
                break;

            case ADDRESS_INCOMPLETE:
                retval = "Address incomplete";
                break;

            case AMBIGUOUS:
                retval = "Ambiguous";
                break;

            case BUSY_HERE:
                retval = "Busy here";
                break;

            case REQUEST_TERMINATED:
                retval = "Request Terminated";
                break;

            case NOT_ACCEPTABLE_HERE:
                retval = "Not Accpetable here";
                break;

            case BAD_EVENT:
                retval = "Bad Event";
                break;

            case REQUEST_PENDING:
                retval = "Request Pending";
                break;

            case SERVER_INTERNAL_ERROR:
                retval = "Server Internal Error";
                break;

            case UNDECIPHERABLE :
                retval = "Undecipherable";
                break;

            case NOT_IMPLEMENTED :
                retval = "Not implemented";
                break;

            case BAD_GATEWAY :
                retval = "Bad gateway";
                break;

            case SERVICE_UNAVAILABLE :
                retval = "Service unavailable";
                break;

            case SERVER_TIMEOUT :
                retval = "Gateway timeout";
                break;

            case VERSION_NOT_SUPPORTED :
                retval = "SIP version not supported";
                break;

            case MESSAGE_TOO_LARGE:
                retval = "Message Too Large";
                break;

            case BUSY_EVERYWHERE :
                retval = "Busy everywhere";
                break;

            case DECLINE:
                retval = "Decline";
                break;

            case DOES_NOT_EXIST_ANYWHERE:
                retval = "Does not exist anywhere";
                break;

            case SESSION_NOT_ACCEPTABLE:
                retval = "Session Not acceptable";
                break;

            default: {
                // null value may cause an exception in setReasonPhrase()
                retval = "";
            }
        }

        return retval;
    }

    /**
     *  set the status code.
     * @param statusCode is the status code to set.
     * @throws IllegalArgumentException if invalid status code.
     */
    public void setStatusCode(int statusCode) throws ParseException {
        if (statusCode < 100 || statusCode > 800) {
            throw new ParseException("bad status code", 0);
        }

        if (statusLine == null) {
            statusLine = new StatusLine();
        }
        statusLine.setStatusCode(statusCode);
    }

    /**
     * Get the status line of the response.
     * @return StatusLine
     */
    public StatusLine getStatusLine() { return statusLine; }

    /**
     * Get the staus code (conveniance function).
     * @return the status code of the status line.
     */
    public int getStatusCode() {
        return statusLine.getStatusCode();
    }

    /**
     * Set the reason phrase.
     * @param reasonPhrase the reason phrase.
     * @throws IllegalArgumentException if null string
     */
    public void setReasonPhrase(String reasonPhrase)
    throws IllegalArgumentException {
        if (reasonPhrase == null)
            throw new IllegalArgumentException("Bad reason phrase");
        if (this.statusLine == null) this.statusLine = new StatusLine();
        this.statusLine.setReasonPhrase(reasonPhrase);
    }

    /**
     *  Get the reason phrase.
     * @return the reason phrase.
     */
    public String getReasonPhrase() {
        if (statusLine == null || statusLine.getReasonPhrase() == null)
            return "";
        else return statusLine.getReasonPhrase();
    }

    /**
     *  Return true if the response is a final response.
     * @param rc is the return code.
     * @return true if the parameter is between the range 200 and 700.
     */
    public static boolean isFinalResponse(int rc) {
        return rc >= 200 && rc < 700;
    }

    /**
     * Is this a final response?
     * @return true if this is a final response.
     */
    public boolean isFinalResponse() {
        return isFinalResponse(statusLine.getStatusCode());
    }

    /**
     * Set the status line field.
     * @param sl Status line to set.
     */
    public void setStatusLine(StatusLine sl) { statusLine = sl; }

    /**
     * Constructor.
     */
    public Response() { super(); }

    /**
     * Check the response structure. Must have from, to CSEQ and VIA
     * headers.
     */
    protected void checkHeaders() throws ParseException {
        if (getCSeqHeader() == null) {
            throw new ParseException
                    (Header.CSEQ, 0);
        }
        if (getTo() == null) {
            throw new ParseException
                    (Header.TO, 0);
        }
        if (getFromHeader() == null) {
            throw new ParseException
                    (Header.FROM, 0);
        }
        if (getViaHeaders() == null) {
            throw new ParseException
                    (Header.VIA, 0);
        }
    }

    /**
     * Encode the SIP Request as a string.
     * @return The string encoded canonical form of the message.
     */

    public String encode() {
        String retval;
        if (statusLine != null)
            retval = statusLine.encode() + super.encode();
        else retval = super.encode();
        return retval;
    }

    /**
     * Make a clone (deep copy) of this object.
     * @return a deep copy of this object.
     */

    public Object clone() {
        Response retval = (Response) super.clone();
        retval.statusLine = (StatusLine) this.statusLine.clone();
        return retval;
    }

    /**
     * Compare for equality.
     * @param other other object to compare with.
     * @return true if the objects match
     */
    public boolean equals(Object other) {
        if (! this.getClass().equals(other.getClass()))
            return false;
        Response that = (Response) other;
        return statusLine.equals(that.statusLine) &&
                super.equals(other);
    }

    /**
     * Encode this into a byte array.
     * This is used when the body has been set as a binary array
     * and you want to encode the body as a byte array for transmission.
     *
     * @return a byte array containing the Request encoded as a byte
     * array.
     */
    public byte[] encodeAsBytes() {
        byte[] slbytes = null;
        if (statusLine != null) {
            try {
                slbytes = statusLine.encode().getBytes("UTF-8");
            } catch (UnsupportedEncodingException ex) {
                InternalErrorHandler.handleException(ex);
            }
        }
        byte[] superbytes = super.encodeAsBytes();
        byte[] retval = new byte[slbytes.length + superbytes.length];
        int i = 0;
        if (slbytes != null) {
            for (i = 0; i < slbytes.length; i++) {
                retval[i] = slbytes[i];
            }
        }

        for (int j = 0; j < superbytes.length; j++, i++) {
            retval[i] = superbytes[j];
        }
        return retval;
    }

    /**
     * Create a new Request from the given response. Note that the
     * RecordRoute Via and CSeqHeader headers are not copied from the response.
     * These have to be added by the caller.
     * This method is useful for generating ACK messages from final
     * responses.
     *
     * @param requestURI is the request URI to use.
     * @param via is the via header to use.
     * @param cseq is the cseq header to use in the generated
     * request.
     * @return a new request obect.
     * @throws SipException if the request can't be created.
     */
    public Request createRequest(URI requestURI,
            ViaHeader via, CSeqHeader cseq) throws SipException {
        Request newRequest = new Request();
        String method = cseq.getMethod();

        newRequest.setMethod(method);
        newRequest.setRequestURI(requestURI);

        if ((equalsIgnoreCase(method, Request.ACK) ||
                equalsIgnoreCase(method, Request.CANCEL)) &&
                this.getTopmostVia().getBranch() != null) {
            // Use the
            via.setBranch(this.getTopmostVia().getBranch());
        }

        newRequest.setHeader(via);
        newRequest.setHeader(cseq);

        Enumeration headerIterator = getHeaders();
        while (headerIterator.hasMoreElements()) {
            Header nextHeader = (Header)headerIterator.nextElement();
            // Some headers do not belong in a Request ....
            if (Message.isResponseHeader(nextHeader) ||
                    nextHeader instanceof ViaList ||
                    nextHeader instanceof CSeqHeader ||
                    nextHeader instanceof ContentTypeHeader ||
                    nextHeader instanceof RecordRouteList) {
                continue;
            }
            if (nextHeader instanceof ToHeader)
                nextHeader = (Header)nextHeader.clone();
            else if (nextHeader instanceof FromHeader)
                nextHeader = (Header)nextHeader.clone();

            newRequest.attachHeader(nextHeader, false);
        }

        return newRequest;
    }

    /**
     * Get the encoded first line.
     *
     * @return the status line encoded.
     *
     */
    public String getFirstLine() {
        if (this.statusLine == null)
            return null;
        else return this.statusLine.encode();
    }

    /**
     * Sets the SIP version string.
     * @param sipVersion the new SIP version
     */
    public void setSIPVersion(String sipVersion) {
        this.statusLine.setSipVersion(sipVersion);
    }

    /**
     * Gets the SIP version string.
     * @return the SIP version string
     */
    public String getSIPVersion() {
        return this.statusLine.getSipVersion(); }

    /**
     * Encodes the object contents as a string
     * @return encoded string of object contents
     */
    public String toString() {
        return statusLine.encode() + super.encode();
    }

}