629 lines
24 KiB
Java
629 lines
24 KiB
Java
/*
|
|
* Copyright (c) 2008-2009, Motorola, Inc.
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* - Neither the name of the Motorola, Inc. nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
package javax.obex;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.util.Calendar;
|
|
import java.security.SecureRandom;
|
|
|
|
/**
|
|
* This class implements the javax.obex.HeaderSet interface for OBEX over
|
|
* RFCOMM.
|
|
* @hide
|
|
*/
|
|
public final class HeaderSet {
|
|
|
|
/**
|
|
* Represents the OBEX Count header. This allows the connection statement to
|
|
* tell the server how many objects it plans to send or retrieve.
|
|
* <P>
|
|
* The value of <code>COUNT</code> is 0xC0 (192).
|
|
*/
|
|
public static final int COUNT = 0xC0;
|
|
|
|
/**
|
|
* Represents the OBEX Name header. This specifies the name of the object.
|
|
* <P>
|
|
* The value of <code>NAME</code> is 0x01 (1).
|
|
*/
|
|
public static final int NAME = 0x01;
|
|
|
|
/**
|
|
* Represents the OBEX Type header. This allows a request to specify the
|
|
* type of the object (e.g. text, html, binary, etc.).
|
|
* <P>
|
|
* The value of <code>TYPE</code> is 0x42 (66).
|
|
*/
|
|
public static final int TYPE = 0x42;
|
|
|
|
/**
|
|
* Represents the OBEX Length header. This is the length of the object in
|
|
* bytes.
|
|
* <P>
|
|
* The value of <code>LENGTH</code> is 0xC3 (195).
|
|
*/
|
|
public static final int LENGTH = 0xC3;
|
|
|
|
/**
|
|
* Represents the OBEX Time header using the ISO 8601 standards. This is the
|
|
* preferred time header.
|
|
* <P>
|
|
* The value of <code>TIME_ISO_8601</code> is 0x44 (68).
|
|
*/
|
|
public static final int TIME_ISO_8601 = 0x44;
|
|
|
|
/**
|
|
* Represents the OBEX Time header using the 4 byte representation. This is
|
|
* only included for backwards compatibility. It represents the number of
|
|
* seconds since January 1, 1970.
|
|
* <P>
|
|
* The value of <code>TIME_4_BYTE</code> is 0xC4 (196).
|
|
*/
|
|
public static final int TIME_4_BYTE = 0xC4;
|
|
|
|
/**
|
|
* Represents the OBEX Description header. This is a text description of the
|
|
* object.
|
|
* <P>
|
|
* The value of <code>DESCRIPTION</code> is 0x05 (5).
|
|
*/
|
|
public static final int DESCRIPTION = 0x05;
|
|
|
|
/**
|
|
* Represents the OBEX Target header. This is the name of the service an
|
|
* operation is targeted to.
|
|
* <P>
|
|
* The value of <code>TARGET</code> is 0x46 (70).
|
|
*/
|
|
public static final int TARGET = 0x46;
|
|
|
|
/**
|
|
* Represents the OBEX HTTP header. This allows an HTTP 1.X header to be
|
|
* included in a request or reply.
|
|
* <P>
|
|
* The value of <code>HTTP</code> is 0x47 (71).
|
|
*/
|
|
public static final int HTTP = 0x47;
|
|
|
|
/**
|
|
* Represents the OBEX BODY header.
|
|
* <P>
|
|
* The value of <code>BODY</code> is 0x48 (72).
|
|
*/
|
|
public static final int BODY = 0x48;
|
|
|
|
/**
|
|
* Represents the OBEX End of BODY header.
|
|
* <P>
|
|
* The value of <code>BODY</code> is 0x49 (73).
|
|
*/
|
|
public static final int END_OF_BODY = 0x49;
|
|
|
|
/**
|
|
* Represents the OBEX Who header. Identifies the OBEX application to
|
|
* determine if the two peers are talking to each other.
|
|
* <P>
|
|
* The value of <code>WHO</code> is 0x4A (74).
|
|
*/
|
|
public static final int WHO = 0x4A;
|
|
|
|
/**
|
|
* Represents the OBEX Connection ID header. Identifies used for OBEX
|
|
* connection multiplexing.
|
|
* <P>
|
|
* The value of <code>CONNECTION_ID</code> is 0xCB (203).
|
|
*/
|
|
|
|
public static final int CONNECTION_ID = 0xCB;
|
|
|
|
/**
|
|
* Represents the OBEX Application Parameter header. This header specifies
|
|
* additional application request and response information.
|
|
* <P>
|
|
* The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
|
|
*/
|
|
public static final int APPLICATION_PARAMETER = 0x4C;
|
|
|
|
/**
|
|
* Represents the OBEX authentication digest-challenge.
|
|
* <P>
|
|
* The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
|
|
*/
|
|
public static final int AUTH_CHALLENGE = 0x4D;
|
|
|
|
/**
|
|
* Represents the OBEX authentication digest-response.
|
|
* <P>
|
|
* The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
|
|
*/
|
|
public static final int AUTH_RESPONSE = 0x4E;
|
|
|
|
/**
|
|
* Represents the OBEX Object Class header. This header specifies the OBEX
|
|
* object class of the object.
|
|
* <P>
|
|
* The value of <code>OBJECT_CLASS</code> is 0x4F (79).
|
|
*/
|
|
public static final int OBJECT_CLASS = 0x4F;
|
|
|
|
private Long mCount; // 4 byte unsigned integer
|
|
|
|
private String mName; // null terminated Unicode text string
|
|
|
|
private String mType; // null terminated ASCII text string
|
|
|
|
private Long mLength; // 4 byte unsigend integer
|
|
|
|
private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
|
|
|
|
private Calendar mByteTime; // 4 byte unsigned integer
|
|
|
|
private String mDescription; // null terminated Unicode text String
|
|
|
|
private byte[] mTarget; // byte sequence
|
|
|
|
private byte[] mHttpHeader; // byte sequence
|
|
|
|
private byte[] mWho; // length prefixed byte sequence
|
|
|
|
private byte[] mAppParam; // byte sequence of the form tag length value
|
|
|
|
private byte[] mObjectClass; // byte sequence
|
|
|
|
private String[] mUnicodeUserDefined; //null terminated unicode string
|
|
|
|
private byte[][] mSequenceUserDefined; // byte sequence user defined
|
|
|
|
private Byte[] mByteUserDefined; // 1 byte
|
|
|
|
private Long[] mIntegerUserDefined; // 4 byte unsigned integer
|
|
|
|
private final SecureRandom mRandom;
|
|
|
|
/*package*/ byte[] nonce;
|
|
|
|
public byte[] mAuthChall; // The authentication challenge header
|
|
|
|
public byte[] mAuthResp; // The authentication response header
|
|
|
|
public byte[] mConnectionID; // THe connection ID
|
|
|
|
public int responseCode;
|
|
|
|
/**
|
|
* Creates new <code>HeaderSet</code> object.
|
|
* @param size the max packet size for this connection
|
|
*/
|
|
public HeaderSet() {
|
|
mUnicodeUserDefined = new String[16];
|
|
mSequenceUserDefined = new byte[16][];
|
|
mByteUserDefined = new Byte[16];
|
|
mIntegerUserDefined = new Long[16];
|
|
responseCode = -1;
|
|
mRandom = new SecureRandom();
|
|
}
|
|
|
|
/**
|
|
* Sets the value of the header identifier to the value provided. The type
|
|
* of object must correspond to the Java type defined in the description of
|
|
* this interface. If <code>null</code> is passed as the
|
|
* <code>headerValue</code> then the header will be removed from the set of
|
|
* headers to include in the next request.
|
|
* @param headerID the identifier to include in the message
|
|
* @param headerValue the value of the header identifier
|
|
* @throws IllegalArgumentException if the header identifier provided is not
|
|
* one defined in this interface or a user-defined header; if the
|
|
* type of <code>headerValue</code> is not the correct Java type as
|
|
* defined in the description of this interface\
|
|
*/
|
|
public void setHeader(int headerID, Object headerValue) {
|
|
long temp = -1;
|
|
|
|
switch (headerID) {
|
|
case COUNT:
|
|
if (!(headerValue instanceof Long)) {
|
|
if (headerValue == null) {
|
|
mCount = null;
|
|
break;
|
|
}
|
|
throw new IllegalArgumentException("Count must be a Long");
|
|
}
|
|
temp = ((Long)headerValue).longValue();
|
|
if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
|
|
throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
|
|
}
|
|
mCount = (Long)headerValue;
|
|
break;
|
|
case NAME:
|
|
if ((headerValue != null) && (!(headerValue instanceof String))) {
|
|
throw new IllegalArgumentException("Name must be a String");
|
|
}
|
|
mName = (String)headerValue;
|
|
break;
|
|
case TYPE:
|
|
if ((headerValue != null) && (!(headerValue instanceof String))) {
|
|
throw new IllegalArgumentException("Type must be a String");
|
|
}
|
|
mType = (String)headerValue;
|
|
break;
|
|
case LENGTH:
|
|
if (!(headerValue instanceof Long)) {
|
|
if (headerValue == null) {
|
|
mLength = null;
|
|
break;
|
|
}
|
|
throw new IllegalArgumentException("Length must be a Long");
|
|
}
|
|
temp = ((Long)headerValue).longValue();
|
|
if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
|
|
throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
|
|
}
|
|
mLength = (Long)headerValue;
|
|
break;
|
|
case TIME_ISO_8601:
|
|
if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
|
|
throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
|
|
}
|
|
mIsoTime = (Calendar)headerValue;
|
|
break;
|
|
case TIME_4_BYTE:
|
|
if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
|
|
throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
|
|
}
|
|
mByteTime = (Calendar)headerValue;
|
|
break;
|
|
case DESCRIPTION:
|
|
if ((headerValue != null) && (!(headerValue instanceof String))) {
|
|
throw new IllegalArgumentException("Description must be a String");
|
|
}
|
|
mDescription = (String)headerValue;
|
|
break;
|
|
case TARGET:
|
|
if (headerValue == null) {
|
|
mTarget = null;
|
|
} else {
|
|
if (!(headerValue instanceof byte[])) {
|
|
throw new IllegalArgumentException("Target must be a byte array");
|
|
} else {
|
|
mTarget = new byte[((byte[])headerValue).length];
|
|
System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
|
|
}
|
|
}
|
|
break;
|
|
case HTTP:
|
|
if (headerValue == null) {
|
|
mHttpHeader = null;
|
|
} else {
|
|
if (!(headerValue instanceof byte[])) {
|
|
throw new IllegalArgumentException("HTTP must be a byte array");
|
|
} else {
|
|
mHttpHeader = new byte[((byte[])headerValue).length];
|
|
System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
|
|
}
|
|
}
|
|
break;
|
|
case WHO:
|
|
if (headerValue == null) {
|
|
mWho = null;
|
|
} else {
|
|
if (!(headerValue instanceof byte[])) {
|
|
throw new IllegalArgumentException("WHO must be a byte array");
|
|
} else {
|
|
mWho = new byte[((byte[])headerValue).length];
|
|
System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
|
|
}
|
|
}
|
|
break;
|
|
case OBJECT_CLASS:
|
|
if (headerValue == null) {
|
|
mObjectClass = null;
|
|
} else {
|
|
if (!(headerValue instanceof byte[])) {
|
|
throw new IllegalArgumentException("Object Class must be a byte array");
|
|
} else {
|
|
mObjectClass = new byte[((byte[])headerValue).length];
|
|
System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
|
|
}
|
|
}
|
|
break;
|
|
case APPLICATION_PARAMETER:
|
|
if (headerValue == null) {
|
|
mAppParam = null;
|
|
} else {
|
|
if (!(headerValue instanceof byte[])) {
|
|
throw new IllegalArgumentException(
|
|
"Application Parameter must be a byte array");
|
|
} else {
|
|
mAppParam = new byte[((byte[])headerValue).length];
|
|
System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
// Verify that it was not a Unicode String user Defined
|
|
if ((headerID >= 0x30) && (headerID <= 0x3F)) {
|
|
if ((headerValue != null) && (!(headerValue instanceof String))) {
|
|
throw new IllegalArgumentException(
|
|
"Unicode String User Defined must be a String");
|
|
}
|
|
mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
|
|
|
|
break;
|
|
}
|
|
// Verify that it was not a byte sequence user defined value
|
|
if ((headerID >= 0x70) && (headerID <= 0x7F)) {
|
|
|
|
if (headerValue == null) {
|
|
mSequenceUserDefined[headerID - 0x70] = null;
|
|
} else {
|
|
if (!(headerValue instanceof byte[])) {
|
|
throw new IllegalArgumentException(
|
|
"Byte Sequence User Defined must be a byte array");
|
|
} else {
|
|
mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
|
|
System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
|
|
0, mSequenceUserDefined[headerID - 0x70].length);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Verify that it was not a Byte user Defined
|
|
if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
|
|
if ((headerValue != null) && (!(headerValue instanceof Byte))) {
|
|
throw new IllegalArgumentException("ByteUser Defined must be a Byte");
|
|
}
|
|
mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
|
|
|
|
break;
|
|
}
|
|
// Verify that is was not the 4 byte unsigned integer user
|
|
// defined header
|
|
if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
|
|
if (!(headerValue instanceof Long)) {
|
|
if (headerValue == null) {
|
|
mIntegerUserDefined[headerID - 0xF0] = null;
|
|
break;
|
|
}
|
|
throw new IllegalArgumentException("Integer User Defined must be a Long");
|
|
}
|
|
temp = ((Long)headerValue).longValue();
|
|
if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
|
|
throw new IllegalArgumentException(
|
|
"Integer User Defined must be between 0 and 0xFFFFFFFF");
|
|
}
|
|
mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
|
|
break;
|
|
}
|
|
throw new IllegalArgumentException("Invalid Header Identifier");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of the header identifier provided. The type of the
|
|
* Object returned is defined in the description of this interface.
|
|
* @param headerID the header identifier whose value is to be returned
|
|
* @return the value of the header provided or <code>null</code> if the
|
|
* header identifier specified is not part of this
|
|
* <code>HeaderSet</code> object
|
|
* @throws IllegalArgumentException if the <code>headerID</code> is not one
|
|
* defined in this interface or any of the user-defined headers
|
|
* @throws IOException if an error occurred in the transport layer during
|
|
* the operation or if the connection has been closed
|
|
*/
|
|
public Object getHeader(int headerID) throws IOException {
|
|
|
|
switch (headerID) {
|
|
case COUNT:
|
|
return mCount;
|
|
case NAME:
|
|
return mName;
|
|
case TYPE:
|
|
return mType;
|
|
case LENGTH:
|
|
return mLength;
|
|
case TIME_ISO_8601:
|
|
return mIsoTime;
|
|
case TIME_4_BYTE:
|
|
return mByteTime;
|
|
case DESCRIPTION:
|
|
return mDescription;
|
|
case TARGET:
|
|
return mTarget;
|
|
case HTTP:
|
|
return mHttpHeader;
|
|
case WHO:
|
|
return mWho;
|
|
case OBJECT_CLASS:
|
|
return mObjectClass;
|
|
case APPLICATION_PARAMETER:
|
|
return mAppParam;
|
|
default:
|
|
// Verify that it was not a Unicode String user Defined
|
|
if ((headerID >= 0x30) && (headerID <= 0x3F)) {
|
|
return mUnicodeUserDefined[headerID - 0x30];
|
|
}
|
|
// Verify that it was not a byte sequence user defined header
|
|
if ((headerID >= 0x70) && (headerID <= 0x7F)) {
|
|
return mSequenceUserDefined[headerID - 0x70];
|
|
}
|
|
// Verify that it was not a byte user defined header
|
|
if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
|
|
return mByteUserDefined[headerID - 0xB0];
|
|
}
|
|
// Verify that it was not a integer user defined header
|
|
if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
|
|
return mIntegerUserDefined[headerID - 0xF0];
|
|
}
|
|
throw new IllegalArgumentException("Invalid Header Identifier");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the list of headers that may be retrieved via the
|
|
* <code>getHeader</code> method that will not return <code>null</code>. In
|
|
* other words, this method returns all the headers that are available in
|
|
* this object.
|
|
* @see #getHeader
|
|
* @return the array of headers that are set in this object or
|
|
* <code>null</code> if no headers are available
|
|
* @throws IOException if an error occurred in the transport layer during
|
|
* the operation or the connection has been closed
|
|
*/
|
|
public int[] getHeaderList() throws IOException {
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
if (mCount != null) {
|
|
out.write(COUNT);
|
|
}
|
|
if (mName != null) {
|
|
out.write(NAME);
|
|
}
|
|
if (mType != null) {
|
|
out.write(TYPE);
|
|
}
|
|
if (mLength != null) {
|
|
out.write(LENGTH);
|
|
}
|
|
if (mIsoTime != null) {
|
|
out.write(TIME_ISO_8601);
|
|
}
|
|
if (mByteTime != null) {
|
|
out.write(TIME_4_BYTE);
|
|
}
|
|
if (mDescription != null) {
|
|
out.write(DESCRIPTION);
|
|
}
|
|
if (mTarget != null) {
|
|
out.write(TARGET);
|
|
}
|
|
if (mHttpHeader != null) {
|
|
out.write(HTTP);
|
|
}
|
|
if (mWho != null) {
|
|
out.write(WHO);
|
|
}
|
|
if (mAppParam != null) {
|
|
out.write(APPLICATION_PARAMETER);
|
|
}
|
|
if (mObjectClass != null) {
|
|
out.write(OBJECT_CLASS);
|
|
}
|
|
|
|
for (int i = 0x30; i < 0x40; i++) {
|
|
if (mUnicodeUserDefined[i - 0x30] != null) {
|
|
out.write(i);
|
|
}
|
|
}
|
|
|
|
for (int i = 0x70; i < 0x80; i++) {
|
|
if (mSequenceUserDefined[i - 0x70] != null) {
|
|
out.write(i);
|
|
}
|
|
}
|
|
|
|
for (int i = 0xB0; i < 0xC0; i++) {
|
|
if (mByteUserDefined[i - 0xB0] != null) {
|
|
out.write(i);
|
|
}
|
|
}
|
|
|
|
for (int i = 0xF0; i < 0x100; i++) {
|
|
if (mIntegerUserDefined[i - 0xF0] != null) {
|
|
out.write(i);
|
|
}
|
|
}
|
|
|
|
byte[] headers = out.toByteArray();
|
|
out.close();
|
|
|
|
if ((headers == null) || (headers.length == 0)) {
|
|
return null;
|
|
}
|
|
|
|
int[] result = new int[headers.length];
|
|
for (int i = 0; i < headers.length; i++) {
|
|
// Convert the byte to a positive integer. That is, an integer
|
|
// between 0 and 256.
|
|
result[i] = headers[i] & 0xFF;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Sets the authentication challenge header. The <code>realm</code> will be
|
|
* encoded based upon the default encoding scheme used by the implementation
|
|
* to encode strings. Therefore, the encoding scheme used to encode the
|
|
* <code>realm</code> is application dependent.
|
|
* @param realm a short description that describes what password to use; if
|
|
* <code>null</code> no realm will be sent in the authentication
|
|
* challenge header
|
|
* @param userID if <code>true</code>, a user ID is required in the reply;
|
|
* if <code>false</code>, no user ID is required
|
|
* @param access if <code>true</code> then full access will be granted if
|
|
* successful; if <code>false</code> then read-only access will be
|
|
* granted if successful
|
|
* @throws IOException
|
|
*/
|
|
public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
|
|
throws IOException {
|
|
|
|
nonce = new byte[16];
|
|
for (int i = 0; i < 16; i++) {
|
|
nonce[i] = (byte)mRandom.nextInt();
|
|
}
|
|
|
|
mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
|
|
}
|
|
|
|
/**
|
|
* Returns the response code received from the server. Response codes are
|
|
* defined in the <code>ResponseCodes</code> class.
|
|
* @see ResponseCodes
|
|
* @return the response code retrieved from the server
|
|
* @throws IOException if an error occurred in the transport layer during
|
|
* the transaction; if this method is called on a
|
|
* <code>HeaderSet</code> object created by calling
|
|
* <code>createHeaderSet()</code> in a <code>ClientSession</code>
|
|
* object; if this object was created by an OBEX server
|
|
*/
|
|
public int getResponseCode() throws IOException {
|
|
if (responseCode == -1) {
|
|
throw new IOException("May not be called on a server");
|
|
} else {
|
|
return responseCode;
|
|
}
|
|
}
|
|
}
|