Home | History | Annotate | Download | only in obex
      1 /*
      2  * Copyright (c) 2014 The Android Open Source Project
      3  * Copyright (c) 2008-2009, Motorola, Inc.
      4  *
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions are met:
      9  *
     10  * - Redistributions of source code must retain the above copyright notice,
     11  * this list of conditions and the following disclaimer.
     12  *
     13  * - Redistributions in binary form must reproduce the above copyright notice,
     14  * this list of conditions and the following disclaimer in the documentation
     15  * and/or other materials provided with the distribution.
     16  *
     17  * - Neither the name of the Motorola, Inc. nor the names of its contributors
     18  * may be used to endorse or promote products derived from this software
     19  * without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 package javax.obex;
     35 
     36 import java.io.ByteArrayOutputStream;
     37 import java.io.IOException;
     38 import java.util.Calendar;
     39 import java.security.SecureRandom;
     40 
     41 /**
     42  * This class implements the javax.obex.HeaderSet interface for OBEX over
     43  * RFCOMM or OBEX over l2cap.
     44  * @hide
     45  */
     46 public final class HeaderSet {
     47 
     48     /**
     49      * Represents the OBEX Count header. This allows the connection statement to
     50      * tell the server how many objects it plans to send or retrieve.
     51      * <P>
     52      * The value of <code>COUNT</code> is 0xC0 (192).
     53      */
     54     public static final int COUNT = 0xC0;
     55 
     56     /**
     57      * Represents the OBEX Name header. This specifies the name of the object.
     58      * <P>
     59      * The value of <code>NAME</code> is 0x01 (1).
     60      */
     61     public static final int NAME = 0x01;
     62 
     63     /**
     64      * Represents the OBEX Type header. This allows a request to specify the
     65      * type of the object (e.g. text, html, binary, etc.).
     66      * <P>
     67      * The value of <code>TYPE</code> is 0x42 (66).
     68      */
     69     public static final int TYPE = 0x42;
     70 
     71     /**
     72      * Represents the OBEX Length header. This is the length of the object in
     73      * bytes.
     74      * <P>
     75      * The value of <code>LENGTH</code> is 0xC3 (195).
     76      */
     77     public static final int LENGTH = 0xC3;
     78 
     79     /**
     80      * Represents the OBEX Time header using the ISO 8601 standards. This is the
     81      * preferred time header.
     82      * <P>
     83      * The value of <code>TIME_ISO_8601</code> is 0x44 (68).
     84      */
     85     public static final int TIME_ISO_8601 = 0x44;
     86 
     87     /**
     88      * Represents the OBEX Time header using the 4 byte representation. This is
     89      * only included for backwards compatibility. It represents the number of
     90      * seconds since January 1, 1970.
     91      * <P>
     92      * The value of <code>TIME_4_BYTE</code> is 0xC4 (196).
     93      */
     94     public static final int TIME_4_BYTE = 0xC4;
     95 
     96     /**
     97      * Represents the OBEX Description header. This is a text description of the
     98      * object.
     99      * <P>
    100      * The value of <code>DESCRIPTION</code> is 0x05 (5).
    101      */
    102     public static final int DESCRIPTION = 0x05;
    103 
    104     /**
    105      * Represents the OBEX Target header. This is the name of the service an
    106      * operation is targeted to.
    107      * <P>
    108      * The value of <code>TARGET</code> is 0x46 (70).
    109      */
    110     public static final int TARGET = 0x46;
    111 
    112     /**
    113      * Represents the OBEX HTTP header. This allows an HTTP 1.X header to be
    114      * included in a request or reply.
    115      * <P>
    116      * The value of <code>HTTP</code> is 0x47 (71).
    117      */
    118     public static final int HTTP = 0x47;
    119 
    120     /**
    121      * Represents the OBEX BODY header.
    122      * <P>
    123      * The value of <code>BODY</code> is 0x48 (72).
    124      */
    125     public static final int BODY = 0x48;
    126 
    127     /**
    128      * Represents the OBEX End of BODY header.
    129      * <P>
    130      * The value of <code>BODY</code> is 0x49 (73).
    131      */
    132     public static final int END_OF_BODY = 0x49;
    133 
    134     /**
    135      * Represents the OBEX Who header. Identifies the OBEX application to
    136      * determine if the two peers are talking to each other.
    137      * <P>
    138      * The value of <code>WHO</code> is 0x4A (74).
    139      */
    140     public static final int WHO = 0x4A;
    141 
    142     /**
    143      * Represents the OBEX Connection ID header. Identifies used for OBEX
    144      * connection multiplexing.
    145      * <P>
    146      * The value of <code>CONNECTION_ID</code> is 0xCB (203).
    147      */
    148 
    149     public static final int CONNECTION_ID = 0xCB;
    150 
    151     /**
    152      * Represents the OBEX Application Parameter header. This header specifies
    153      * additional application request and response information.
    154      * <P>
    155      * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
    156      */
    157     public static final int APPLICATION_PARAMETER = 0x4C;
    158 
    159     /**
    160      * Represents the OBEX authentication digest-challenge.
    161      * <P>
    162      * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
    163      */
    164     public static final int AUTH_CHALLENGE = 0x4D;
    165 
    166     /**
    167      * Represents the OBEX authentication digest-response.
    168      * <P>
    169      * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
    170      */
    171     public static final int AUTH_RESPONSE = 0x4E;
    172 
    173     /**
    174      * Represents the OBEX Object Class header. This header specifies the OBEX
    175      * object class of the object.
    176      * <P>
    177      * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
    178      */
    179     public static final int OBJECT_CLASS = 0x4F;
    180 
    181     /**
    182      * Represents the OBEX Single Response Mode (SRM). This header is used
    183      * for Single response mode, introduced in OBEX 1.5.
    184      * <P>
    185      * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151).
    186      */
    187     public static final int SINGLE_RESPONSE_MODE = 0x97;
    188 
    189     /**
    190      * Represents the OBEX Single Response Mode Parameters. This header is used
    191      * for Single response mode, introduced in OBEX 1.5.
    192      * <P>
    193      * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152).
    194      */
    195     public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98;
    196 
    197     private Long mCount; // 4 byte unsigned integer
    198 
    199     private String mName; // null terminated Unicode text string
    200 
    201     private boolean mEmptyName;
    202 
    203     private String mType; // null terminated ASCII text string
    204 
    205     private Long mLength; // 4 byte unsigend integer
    206 
    207     private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
    208 
    209     private Calendar mByteTime; // 4 byte unsigned integer
    210 
    211     private String mDescription; // null terminated Unicode text String
    212 
    213     private byte[] mTarget; // byte sequence
    214 
    215     private byte[] mHttpHeader; // byte sequence
    216 
    217     private byte[] mWho; // length prefixed byte sequence
    218 
    219     private byte[] mAppParam; // byte sequence of the form tag length value
    220 
    221     private byte[] mObjectClass; // byte sequence
    222 
    223     private String[] mUnicodeUserDefined; // null terminated unicode string
    224 
    225     private byte[][] mSequenceUserDefined; // byte sequence user defined
    226 
    227     private Byte[] mByteUserDefined; // 1 byte
    228 
    229     private Long[] mIntegerUserDefined; // 4 byte unsigned integer
    230 
    231     private SecureRandom mRandom = null;
    232 
    233     private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM
    234 
    235     private Byte mSrmParam; // byte representing the SRM parameters - only "wait"
    236                             // is supported by Bluetooth
    237 
    238     /*package*/ byte[] nonce;
    239 
    240     public byte[] mAuthChall; // The authentication challenge header
    241 
    242     public byte[] mAuthResp; // The authentication response header
    243 
    244     public byte[] mConnectionID; // THe connection ID
    245 
    246     public int responseCode;
    247 
    248     /**
    249      * Creates new <code>HeaderSet</code> object.
    250      * @param size the max packet size for this connection
    251      */
    252     public HeaderSet() {
    253         mUnicodeUserDefined = new String[16];
    254         mSequenceUserDefined = new byte[16][];
    255         mByteUserDefined = new Byte[16];
    256         mIntegerUserDefined = new Long[16];
    257         responseCode = -1;
    258     }
    259 
    260     /**
    261      * Sets flag for special "value" of NAME header which should be empty. This
    262      * is not the same as NAME header with empty string in which case it will
    263      * have length of 5 bytes. It should be 3 bytes with only header id and
    264      * length field.
    265      */
    266     public void setEmptyNameHeader() {
    267         mName = null;
    268         mEmptyName = true;
    269     }
    270 
    271     /**
    272      * Gets flag for special "value" of NAME header which should be empty. See
    273      * above.
    274      */
    275     public boolean getEmptyNameHeader() {
    276         return mEmptyName;
    277     }
    278 
    279     /**
    280      * Sets the value of the header identifier to the value provided. The type
    281      * of object must correspond to the Java type defined in the description of
    282      * this interface. If <code>null</code> is passed as the
    283      * <code>headerValue</code> then the header will be removed from the set of
    284      * headers to include in the next request.
    285      * @param headerID the identifier to include in the message
    286      * @param headerValue the value of the header identifier
    287      * @throws IllegalArgumentException if the header identifier provided is not
    288      *         one defined in this interface or a user-defined header; if the
    289      *         type of <code>headerValue</code> is not the correct Java type as
    290      *         defined in the description of this interface\
    291      */
    292     public void setHeader(int headerID, Object headerValue) {
    293         long temp = -1;
    294 
    295         switch (headerID) {
    296             case COUNT:
    297                 if (!(headerValue instanceof Long)) {
    298                     if (headerValue == null) {
    299                         mCount = null;
    300                         break;
    301                     }
    302                     throw new IllegalArgumentException("Count must be a Long");
    303                 }
    304                 temp = ((Long)headerValue).longValue();
    305                 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
    306                     throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
    307                 }
    308                 mCount = (Long)headerValue;
    309                 break;
    310             case NAME:
    311                 if ((headerValue != null) && (!(headerValue instanceof String))) {
    312                     throw new IllegalArgumentException("Name must be a String");
    313                 }
    314                 mEmptyName = false;
    315                 mName = (String)headerValue;
    316                 break;
    317             case TYPE:
    318                 if ((headerValue != null) && (!(headerValue instanceof String))) {
    319                     throw new IllegalArgumentException("Type must be a String");
    320                 }
    321                 mType = (String)headerValue;
    322                 break;
    323             case LENGTH:
    324                 if (!(headerValue instanceof Long)) {
    325                     if (headerValue == null) {
    326                         mLength = null;
    327                         break;
    328                     }
    329                     throw new IllegalArgumentException("Length must be a Long");
    330                 }
    331                 temp = ((Long)headerValue).longValue();
    332                 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
    333                     throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
    334                 }
    335                 mLength = (Long)headerValue;
    336                 break;
    337             case TIME_ISO_8601:
    338                 if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
    339                     throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
    340                 }
    341                 mIsoTime = (Calendar)headerValue;
    342                 break;
    343             case TIME_4_BYTE:
    344                 if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
    345                     throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
    346                 }
    347                 mByteTime = (Calendar)headerValue;
    348                 break;
    349             case DESCRIPTION:
    350                 if ((headerValue != null) && (!(headerValue instanceof String))) {
    351                     throw new IllegalArgumentException("Description must be a String");
    352                 }
    353                 mDescription = (String)headerValue;
    354                 break;
    355             case TARGET:
    356                 if (headerValue == null) {
    357                     mTarget = null;
    358                 } else {
    359                     if (!(headerValue instanceof byte[])) {
    360                         throw new IllegalArgumentException("Target must be a byte array");
    361                     } else {
    362                         mTarget = new byte[((byte[])headerValue).length];
    363                         System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
    364                     }
    365                 }
    366                 break;
    367             case HTTP:
    368                 if (headerValue == null) {
    369                     mHttpHeader = null;
    370                 } else {
    371                     if (!(headerValue instanceof byte[])) {
    372                         throw new IllegalArgumentException("HTTP must be a byte array");
    373                     } else {
    374                         mHttpHeader = new byte[((byte[])headerValue).length];
    375                         System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
    376                     }
    377                 }
    378                 break;
    379             case WHO:
    380                 if (headerValue == null) {
    381                     mWho = null;
    382                 } else {
    383                     if (!(headerValue instanceof byte[])) {
    384                         throw new IllegalArgumentException("WHO must be a byte array");
    385                     } else {
    386                         mWho = new byte[((byte[])headerValue).length];
    387                         System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
    388                     }
    389                 }
    390                 break;
    391             case OBJECT_CLASS:
    392                 if (headerValue == null) {
    393                     mObjectClass = null;
    394                 } else {
    395                     if (!(headerValue instanceof byte[])) {
    396                         throw new IllegalArgumentException("Object Class must be a byte array");
    397                     } else {
    398                         mObjectClass = new byte[((byte[])headerValue).length];
    399                         System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
    400                     }
    401                 }
    402                 break;
    403             case APPLICATION_PARAMETER:
    404                 if (headerValue == null) {
    405                     mAppParam = null;
    406                 } else {
    407                     if (!(headerValue instanceof byte[])) {
    408                         throw new IllegalArgumentException(
    409                                 "Application Parameter must be a byte array");
    410                     } else {
    411                         mAppParam = new byte[((byte[])headerValue).length];
    412                         System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
    413                     }
    414                 }
    415                 break;
    416             case SINGLE_RESPONSE_MODE:
    417                 if (headerValue == null) {
    418                     mSingleResponseMode = null;
    419                 } else {
    420                     if (!(headerValue instanceof Byte)) {
    421                         throw new IllegalArgumentException(
    422                                 "Single Response Mode must be a Byte");
    423                     } else {
    424                         mSingleResponseMode = (Byte)headerValue;
    425                     }
    426                 }
    427                 break;
    428             case SINGLE_RESPONSE_MODE_PARAMETER:
    429                 if (headerValue == null) {
    430                     mSrmParam = null;
    431                 } else {
    432                     if (!(headerValue instanceof Byte)) {
    433                         throw new IllegalArgumentException(
    434                                 "Single Response Mode Parameter must be a Byte");
    435                     } else {
    436                         mSrmParam = (Byte)headerValue;
    437                     }
    438                 }
    439                 break;
    440             default:
    441                 // Verify that it was not a Unicode String user Defined
    442                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
    443                     if ((headerValue != null) && (!(headerValue instanceof String))) {
    444                         throw new IllegalArgumentException(
    445                                 "Unicode String User Defined must be a String");
    446                     }
    447                     mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
    448 
    449                     break;
    450                 }
    451                 // Verify that it was not a byte sequence user defined value
    452                 if ((headerID >= 0x70) && (headerID <= 0x7F)) {
    453 
    454                     if (headerValue == null) {
    455                         mSequenceUserDefined[headerID - 0x70] = null;
    456                     } else {
    457                         if (!(headerValue instanceof byte[])) {
    458                             throw new IllegalArgumentException(
    459                                     "Byte Sequence User Defined must be a byte array");
    460                         } else {
    461                             mSequenceUserDefined[headerID - 0x70] = new byte[((byte[])headerValue).length];
    462                             System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
    463                                     0, mSequenceUserDefined[headerID - 0x70].length);
    464                         }
    465                     }
    466                     break;
    467                 }
    468                 // Verify that it was not a Byte user Defined
    469                 if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
    470                     if ((headerValue != null) && (!(headerValue instanceof Byte))) {
    471                         throw new IllegalArgumentException("ByteUser Defined must be a Byte");
    472                     }
    473                     mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
    474 
    475                     break;
    476                 }
    477                 // Verify that is was not the 4 byte unsigned integer user
    478                 // defined header
    479                 if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
    480                     if (!(headerValue instanceof Long)) {
    481                         if (headerValue == null) {
    482                             mIntegerUserDefined[headerID - 0xF0] = null;
    483                             break;
    484                         }
    485                         throw new IllegalArgumentException("Integer User Defined must be a Long");
    486                     }
    487                     temp = ((Long)headerValue).longValue();
    488                     if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
    489                         throw new IllegalArgumentException(
    490                                 "Integer User Defined must be between 0 and 0xFFFFFFFF");
    491                     }
    492                     mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
    493                     break;
    494                 }
    495                 throw new IllegalArgumentException("Invalid Header Identifier");
    496         }
    497     }
    498 
    499     /**
    500      * Retrieves the value of the header identifier provided. The type of the
    501      * Object returned is defined in the description of this interface.
    502      * @param headerID the header identifier whose value is to be returned
    503      * @return the value of the header provided or <code>null</code> if the
    504      *         header identifier specified is not part of this
    505      *         <code>HeaderSet</code> object
    506      * @throws IllegalArgumentException if the <code>headerID</code> is not one
    507      *         defined in this interface or any of the user-defined headers
    508      * @throws IOException if an error occurred in the transport layer during
    509      *         the operation or if the connection has been closed
    510      */
    511     public Object getHeader(int headerID) throws IOException {
    512 
    513         switch (headerID) {
    514             case COUNT:
    515                 return mCount;
    516             case NAME:
    517                 return mName;
    518             case TYPE:
    519                 return mType;
    520             case LENGTH:
    521                 return mLength;
    522             case TIME_ISO_8601:
    523                 return mIsoTime;
    524             case TIME_4_BYTE:
    525                 return mByteTime;
    526             case DESCRIPTION:
    527                 return mDescription;
    528             case TARGET:
    529                 return mTarget;
    530             case HTTP:
    531                 return mHttpHeader;
    532             case WHO:
    533                 return mWho;
    534             case CONNECTION_ID:
    535                 return mConnectionID;
    536             case OBJECT_CLASS:
    537                 return mObjectClass;
    538             case APPLICATION_PARAMETER:
    539                 return mAppParam;
    540             case SINGLE_RESPONSE_MODE:
    541                 return mSingleResponseMode;
    542             case SINGLE_RESPONSE_MODE_PARAMETER:
    543                 return mSrmParam;
    544             default:
    545                 // Verify that it was not a Unicode String user Defined
    546                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
    547                     return mUnicodeUserDefined[headerID - 0x30];
    548                 }
    549                 // Verify that it was not a byte sequence user defined header
    550                 if ((headerID >= 0x70) && (headerID <= 0x7F)) {
    551                     return mSequenceUserDefined[headerID - 0x70];
    552                 }
    553                 // Verify that it was not a byte user defined header
    554                 if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
    555                     return mByteUserDefined[headerID - 0xB0];
    556                 }
    557                 // Verify that it was not a integer user defined header
    558                 if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
    559                     return mIntegerUserDefined[headerID - 0xF0];
    560                 }
    561                 throw new IllegalArgumentException("Invalid Header Identifier");
    562         }
    563     }
    564 
    565     /**
    566      * Retrieves the list of headers that may be retrieved via the
    567      * <code>getHeader</code> method that will not return <code>null</code>. In
    568      * other words, this method returns all the headers that are available in
    569      * this object.
    570      * @see #getHeader
    571      * @return the array of headers that are set in this object or
    572      *         <code>null</code> if no headers are available
    573      * @throws IOException if an error occurred in the transport layer during
    574      *         the operation or the connection has been closed
    575      */
    576     public int[] getHeaderList() throws IOException {
    577         ByteArrayOutputStream out = new ByteArrayOutputStream();
    578 
    579         if (mCount != null) {
    580             out.write(COUNT);
    581         }
    582         if (mName != null) {
    583             out.write(NAME);
    584         }
    585         if (mType != null) {
    586             out.write(TYPE);
    587         }
    588         if (mLength != null) {
    589             out.write(LENGTH);
    590         }
    591         if (mIsoTime != null) {
    592             out.write(TIME_ISO_8601);
    593         }
    594         if (mByteTime != null) {
    595             out.write(TIME_4_BYTE);
    596         }
    597         if (mDescription != null) {
    598             out.write(DESCRIPTION);
    599         }
    600         if (mTarget != null) {
    601             out.write(TARGET);
    602         }
    603         if (mHttpHeader != null) {
    604             out.write(HTTP);
    605         }
    606         if (mWho != null) {
    607             out.write(WHO);
    608         }
    609         if (mAppParam != null) {
    610             out.write(APPLICATION_PARAMETER);
    611         }
    612         if (mObjectClass != null) {
    613             out.write(OBJECT_CLASS);
    614         }
    615         if(mSingleResponseMode != null) {
    616             out.write(SINGLE_RESPONSE_MODE);
    617         }
    618         if(mSrmParam != null) {
    619             out.write(SINGLE_RESPONSE_MODE_PARAMETER);
    620         }
    621 
    622         for (int i = 0x30; i < 0x40; i++) {
    623             if (mUnicodeUserDefined[i - 0x30] != null) {
    624                 out.write(i);
    625             }
    626         }
    627 
    628         for (int i = 0x70; i < 0x80; i++) {
    629             if (mSequenceUserDefined[i - 0x70] != null) {
    630                 out.write(i);
    631             }
    632         }
    633 
    634         for (int i = 0xB0; i < 0xC0; i++) {
    635             if (mByteUserDefined[i - 0xB0] != null) {
    636                 out.write(i);
    637             }
    638         }
    639 
    640         for (int i = 0xF0; i < 0x100; i++) {
    641             if (mIntegerUserDefined[i - 0xF0] != null) {
    642                 out.write(i);
    643             }
    644         }
    645 
    646         byte[] headers = out.toByteArray();
    647         out.close();
    648 
    649         if ((headers == null) || (headers.length == 0)) {
    650             return null;
    651         }
    652 
    653         int[] result = new int[headers.length];
    654         for (int i = 0; i < headers.length; i++) {
    655             // Convert the byte to a positive integer.  That is, an integer
    656             // between 0 and 256.
    657             result[i] = headers[i] & 0xFF;
    658         }
    659 
    660         return result;
    661     }
    662 
    663     /**
    664      * Sets the authentication challenge header. The <code>realm</code> will be
    665      * encoded based upon the default encoding scheme used by the implementation
    666      * to encode strings. Therefore, the encoding scheme used to encode the
    667      * <code>realm</code> is application dependent.
    668      * @param realm a short description that describes what password to use; if
    669      *        <code>null</code> no realm will be sent in the authentication
    670      *        challenge header
    671      * @param userID if <code>true</code>, a user ID is required in the reply;
    672      *        if <code>false</code>, no user ID is required
    673      * @param access if <code>true</code> then full access will be granted if
    674      *        successful; if <code>false</code> then read-only access will be
    675      *        granted if successful
    676      * @throws IOException
    677      */
    678     public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
    679             throws IOException {
    680 
    681         nonce = new byte[16];
    682         if(mRandom == null) {
    683             mRandom = new SecureRandom();
    684         }
    685         for (int i = 0; i < 16; i++) {
    686             nonce[i] = (byte)mRandom.nextInt();
    687         }
    688 
    689         mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
    690     }
    691 
    692     /**
    693      * Returns the response code received from the server. Response codes are
    694      * defined in the <code>ResponseCodes</code> class.
    695      * @see ResponseCodes
    696      * @return the response code retrieved from the server
    697      * @throws IOException if an error occurred in the transport layer during
    698      *         the transaction; if this method is called on a
    699      *         <code>HeaderSet</code> object created by calling
    700      *         <code>createHeaderSet()</code> in a <code>ClientSession</code>
    701      *         object; if this object was created by an OBEX server
    702      */
    703     public int getResponseCode() throws IOException {
    704         if (responseCode == -1) {
    705             throw new IOException("May not be called on a server");
    706         } else {
    707             return responseCode;
    708         }
    709     }
    710 }
    711