|  | /* | 
|  | * Copyright (c) 2014 The Android Open Source Project | 
|  | * 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 or OBEX over l2cap. | 
|  | * @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; | 
|  |  | 
|  | /** | 
|  | * Represents the OBEX Single Response Mode (SRM). This header is used | 
|  | * for Single response mode, introduced in OBEX 1.5. | 
|  | * <P> | 
|  | * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151). | 
|  | */ | 
|  | public static final int SINGLE_RESPONSE_MODE = 0x97; | 
|  |  | 
|  | /** | 
|  | * Represents the OBEX Single Response Mode Parameters. This header is used | 
|  | * for Single response mode, introduced in OBEX 1.5. | 
|  | * <P> | 
|  | * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152). | 
|  | */ | 
|  | public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98; | 
|  |  | 
|  | private Long mCount; // 4 byte unsigned integer | 
|  |  | 
|  | private String mName; // null terminated Unicode text string | 
|  |  | 
|  | private boolean mEmptyName; | 
|  |  | 
|  | 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 SecureRandom mRandom = null; | 
|  |  | 
|  | private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM | 
|  |  | 
|  | private Byte mSrmParam; // byte representing the SRM parameters - only "wait" | 
|  | // is supported by Bluetooth | 
|  |  | 
|  | /*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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets flag for special "value" of NAME header which should be empty. This | 
|  | * is not the same as NAME header with empty string in which case it will | 
|  | * have length of 5 bytes. It should be 3 bytes with only header id and | 
|  | * length field. | 
|  | */ | 
|  | public void setEmptyNameHeader() { | 
|  | mName = null; | 
|  | mEmptyName = true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets flag for special "value" of NAME header which should be empty. See | 
|  | * above. | 
|  | */ | 
|  | public boolean getEmptyNameHeader() { | 
|  | return mEmptyName; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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"); | 
|  | } | 
|  | mEmptyName = false; | 
|  | 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; | 
|  | case SINGLE_RESPONSE_MODE: | 
|  | if (headerValue == null) { | 
|  | mSingleResponseMode = null; | 
|  | } else { | 
|  | if (!(headerValue instanceof Byte)) { | 
|  | throw new IllegalArgumentException( | 
|  | "Single Response Mode must be a Byte"); | 
|  | } else { | 
|  | mSingleResponseMode = (Byte)headerValue; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case SINGLE_RESPONSE_MODE_PARAMETER: | 
|  | if (headerValue == null) { | 
|  | mSrmParam = null; | 
|  | } else { | 
|  | if (!(headerValue instanceof Byte)) { | 
|  | throw new IllegalArgumentException( | 
|  | "Single Response Mode Parameter must be a Byte"); | 
|  | } else { | 
|  | mSrmParam = (Byte)headerValue; | 
|  | } | 
|  | } | 
|  | 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 CONNECTION_ID: | 
|  | return mConnectionID; | 
|  | case OBJECT_CLASS: | 
|  | return mObjectClass; | 
|  | case APPLICATION_PARAMETER: | 
|  | return mAppParam; | 
|  | case SINGLE_RESPONSE_MODE: | 
|  | return mSingleResponseMode; | 
|  | case SINGLE_RESPONSE_MODE_PARAMETER: | 
|  | return mSrmParam; | 
|  | 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); | 
|  | } | 
|  | if(mSingleResponseMode != null) { | 
|  | out.write(SINGLE_RESPONSE_MODE); | 
|  | } | 
|  | if(mSrmParam != null) { | 
|  | out.write(SINGLE_RESPONSE_MODE_PARAMETER); | 
|  | } | 
|  |  | 
|  | 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]; | 
|  | if(mRandom == null) { | 
|  | mRandom = new SecureRandom(); | 
|  | } | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } |