/* * Portions Copyright 2000-2009 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.*; import gov.nist.siplite.SIPErrorCodes; /** * 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; /** * Gets the reason phrase. * @param rc the reason code * @return the reason phrase as a string */ public static String getReasonPhrase(int rc) { return SIPErrorCodes.getReasonPhrase(rc); } /** * 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(); } }