• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.obex;
35 
36 import java.io.ByteArrayOutputStream;
37 import java.io.IOException;
38 import java.security.SecureRandom;
39 import java.util.Arrays;
40 import java.util.Calendar;
41 
42 /**
43  * This class implements the com.android.obex.HeaderSet interface for OBEX over
44  * RFCOMM or OBEX over l2cap.
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      * @hide
126      */
127     public static final int BODY = 0x48;
128 
129     /**
130      * Represents the OBEX End of BODY header.
131      * <P>
132      * The value of <code>BODY</code> is 0x49 (73).
133      *
134      * @hide
135      */
136     public static final int END_OF_BODY = 0x49;
137 
138     /**
139      * Represents the OBEX Who header. Identifies the OBEX application to
140      * determine if the two peers are talking to each other.
141      * <P>
142      * The value of <code>WHO</code> is 0x4A (74).
143      */
144     public static final int WHO = 0x4A;
145 
146     /**
147      * Represents the OBEX Connection ID header. Identifies used for OBEX
148      * connection multiplexing.
149      * <P>
150      * The value of <code>CONNECTION_ID</code> is 0xCB (203).
151      *
152      * @hide
153      */
154     public static final int CONNECTION_ID = 0xCB;
155 
156     /**
157      * Represents the OBEX Application Parameter header. This header specifies
158      * additional application request and response information.
159      * <P>
160      * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76).
161      */
162     public static final int APPLICATION_PARAMETER = 0x4C;
163 
164     /**
165      * Represents the OBEX authentication digest-challenge.
166      * <P>
167      * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77).
168      *
169      * @hide
170      */
171     public static final int AUTH_CHALLENGE = 0x4D;
172 
173     /**
174      * Represents the OBEX authentication digest-response.
175      * <P>
176      * The value of <code>AUTH_RESPONSE</code> is 0x4E (78).
177      *
178      * @hide
179      */
180     public static final int AUTH_RESPONSE = 0x4E;
181 
182     /**
183      * Represents the OBEX Object Class header. This header specifies the OBEX
184      * object class of the object.
185      * <P>
186      * The value of <code>OBJECT_CLASS</code> is 0x4F (79).
187      */
188     public static final int OBJECT_CLASS = 0x4F;
189 
190     /**
191      * Represents the OBEX Single Response Mode (SRM). This header is used
192      * for Single response mode, introduced in OBEX 1.5.
193      * <P>
194      * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151).
195      *
196      * @hide
197      */
198     public static final int SINGLE_RESPONSE_MODE = 0x97;
199 
200     /**
201      * Represents the OBEX Single Response Mode Parameters. This header is used
202      * for Single response mode, introduced in OBEX 1.5.
203      * <P>
204      * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152).
205      *
206      * @hide
207      */
208     public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98;
209 
210     private Long mCount; // 4 byte unsigned integer
211 
212     private String mName; // null terminated Unicode text string
213 
214     private boolean mEmptyName;
215 
216     private String mType; // null terminated ASCII text string
217 
218     private Long mLength; // 4 byte unsigend integer
219 
220     private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ
221 
222     private Calendar mByteTime; // 4 byte unsigned integer
223 
224     private String mDescription; // null terminated Unicode text String
225 
226     private byte[] mTarget; // byte sequence
227 
228     private byte[] mHttpHeader; // byte sequence
229 
230     private byte[] mWho; // length prefixed byte sequence
231 
232     private byte[] mAppParam; // byte sequence of the form tag length value
233 
234     private byte[] mObjectClass; // byte sequence
235 
236     private String[] mUnicodeUserDefined; // null terminated unicode string
237 
238     private byte[][] mSequenceUserDefined; // byte sequence user defined
239 
240     private Byte[] mByteUserDefined; // 1 byte
241 
242     private Long[] mIntegerUserDefined; // 4 byte unsigned integer
243 
244     private SecureRandom mRandom = null;
245 
246     private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM
247 
248     private Byte mSrmParam; // byte representing the SRM parameters - only "wait"
249                             // is supported by Bluetooth
250 
251     /*package*/ byte[] nonce;
252 
253     public byte[] mAuthChall; // The authentication challenge header
254 
255     public byte[] mAuthResp; // The authentication response header
256 
257     public byte[] mConnectionID; // THe connection ID
258 
259     public int responseCode;
260 
261     /**
262      * Creates new <code>HeaderSet</code> object.
263      */
HeaderSet()264     public HeaderSet() {
265         mUnicodeUserDefined = new String[16];
266         mSequenceUserDefined = new byte[16][];
267         mByteUserDefined = new Byte[16];
268         mIntegerUserDefined = new Long[16];
269         responseCode = -1;
270     }
271 
272     /**
273      * Sets flag for special "value" of NAME header which should be empty. This
274      * is not the same as NAME header with empty string in which case it will
275      * have length of 5 bytes. It should be 3 bytes with only header id and
276      * length field.
277      */
setEmptyNameHeader()278     public void setEmptyNameHeader() {
279         mName = null;
280         mEmptyName = true;
281     }
282 
283     /**
284      * Gets flag for special "value" of NAME header which should be empty. See
285      * above.
286      *
287      * @hide
288      */
getEmptyNameHeader()289     public boolean getEmptyNameHeader() {
290         return mEmptyName;
291     }
292 
293     /**
294      * Sets the value of the header identifier to the value provided. The type
295      * of object must correspond to the Java type defined in the description of
296      * this interface. If <code>null</code> is passed as the
297      * <code>headerValue</code> then the header will be removed from the set of
298      * headers to include in the next request.
299      * @param headerID the identifier to include in the message
300      * @param headerValue the value of the header identifier
301      * @throws IllegalArgumentException if the header identifier provided is not
302      *         one defined in this interface or a user-defined header; if the
303      *         type of <code>headerValue</code> is not the correct Java type as
304      *         defined in the description of this interface\
305      */
setHeader(int headerID, Object headerValue)306     public void setHeader(int headerID, Object headerValue) {
307         long temp = -1;
308 
309         switch (headerID) {
310             case COUNT:
311                 if (!(headerValue instanceof Long)) {
312                     if (headerValue == null) {
313                         mCount = null;
314                         break;
315                     }
316                     throw new IllegalArgumentException("Count must be a Long");
317                 }
318                 temp = ((Long)headerValue).longValue();
319                 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
320                     throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF");
321                 }
322                 mCount = (Long)headerValue;
323                 break;
324             case NAME:
325                 if ((headerValue != null) && (!(headerValue instanceof String))) {
326                     throw new IllegalArgumentException("Name must be a String");
327                 }
328                 mEmptyName = false;
329                 mName = (String)headerValue;
330                 break;
331             case TYPE:
332                 if ((headerValue != null) && (!(headerValue instanceof String))) {
333                     throw new IllegalArgumentException("Type must be a String");
334                 }
335                 mType = (String)headerValue;
336                 break;
337             case LENGTH:
338                 if (!(headerValue instanceof Long)) {
339                     if (headerValue == null) {
340                         mLength = null;
341                         break;
342                     }
343                     throw new IllegalArgumentException("Length must be a Long");
344                 }
345                 temp = ((Long)headerValue).longValue();
346                 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
347                     throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF");
348                 }
349                 mLength = (Long)headerValue;
350                 break;
351             case TIME_ISO_8601:
352                 if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
353                     throw new IllegalArgumentException("Time ISO 8601 must be a Calendar");
354                 }
355                 mIsoTime = (Calendar)headerValue;
356                 break;
357             case TIME_4_BYTE:
358                 if ((headerValue != null) && (!(headerValue instanceof Calendar))) {
359                     throw new IllegalArgumentException("Time 4 Byte must be a Calendar");
360                 }
361                 mByteTime = (Calendar)headerValue;
362                 break;
363             case DESCRIPTION:
364                 if ((headerValue != null) && (!(headerValue instanceof String))) {
365                     throw new IllegalArgumentException("Description must be a String");
366                 }
367                 mDescription = (String)headerValue;
368                 break;
369             case TARGET:
370                 if (headerValue == null) {
371                     mTarget = null;
372                 } else {
373                     if (!(headerValue instanceof byte[])) {
374                         throw new IllegalArgumentException("Target must be a byte array");
375                     } else {
376                         mTarget = new byte[((byte[])headerValue).length];
377                         System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length);
378                     }
379                 }
380                 break;
381             case HTTP:
382                 if (headerValue == null) {
383                     mHttpHeader = null;
384                 } else {
385                     if (!(headerValue instanceof byte[])) {
386                         throw new IllegalArgumentException("HTTP must be a byte array");
387                     } else {
388                         mHttpHeader = new byte[((byte[])headerValue).length];
389                         System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length);
390                     }
391                 }
392                 break;
393             case WHO:
394                 if (headerValue == null) {
395                     mWho = null;
396                 } else {
397                     if (!(headerValue instanceof byte[])) {
398                         throw new IllegalArgumentException("WHO must be a byte array");
399                     } else {
400                         mWho = new byte[((byte[])headerValue).length];
401                         System.arraycopy(headerValue, 0, mWho, 0, mWho.length);
402                     }
403                 }
404                 break;
405             case OBJECT_CLASS:
406                 if (headerValue == null) {
407                     mObjectClass = null;
408                 } else {
409                     if (!(headerValue instanceof byte[])) {
410                         throw new IllegalArgumentException("Object Class must be a byte array");
411                     } else {
412                         mObjectClass = new byte[((byte[])headerValue).length];
413                         System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length);
414                     }
415                 }
416                 break;
417             case APPLICATION_PARAMETER:
418                 if (headerValue == null) {
419                     mAppParam = null;
420                 } else {
421                     if (!(headerValue instanceof byte[])) {
422                         throw new IllegalArgumentException(
423                                 "Application Parameter must be a byte array");
424                     } else {
425                         mAppParam = new byte[((byte[])headerValue).length];
426                         System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length);
427                     }
428                 }
429                 break;
430             case SINGLE_RESPONSE_MODE:
431                 if (headerValue == null) {
432                     mSingleResponseMode = null;
433                 } else {
434                     if (!(headerValue instanceof Byte)) {
435                         throw new IllegalArgumentException(
436                                 "Single Response Mode must be a Byte");
437                     } else {
438                         mSingleResponseMode = (Byte)headerValue;
439                     }
440                 }
441                 break;
442             case SINGLE_RESPONSE_MODE_PARAMETER:
443                 if (headerValue == null) {
444                     mSrmParam = null;
445                 } else {
446                     if (!(headerValue instanceof Byte)) {
447                         throw new IllegalArgumentException(
448                                 "Single Response Mode Parameter must be a Byte");
449                     } else {
450                         mSrmParam = (Byte)headerValue;
451                     }
452                 }
453                 break;
454             default:
455                 // Verify that it was not a Unicode String user Defined
456                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
457                     if ((headerValue != null) && (!(headerValue instanceof String))) {
458                         throw new IllegalArgumentException(
459                                 "Unicode String User Defined must be a String");
460                     }
461                     mUnicodeUserDefined[headerID - 0x30] = (String)headerValue;
462 
463                     break;
464                 }
465                 // Verify that it was not a byte sequence user defined value
466                 if ((headerID >= 0x70) && (headerID <= 0x7F)) {
467 
468                     if (headerValue == null) {
469                         mSequenceUserDefined[headerID - 0x70] = null;
470                     } else {
471                         if (!(headerValue instanceof byte[])) {
472                             throw new IllegalArgumentException(
473                                     "Byte Sequence User Defined must be a byte array");
474                         } else {
475                             mSequenceUserDefined[headerID - 0x70]
476                                     = new byte[((byte[])headerValue).length];
477                             System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70],
478                                     0, mSequenceUserDefined[headerID - 0x70].length);
479                         }
480                     }
481                     break;
482                 }
483                 // Verify that it was not a Byte user Defined
484                 if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
485                     if ((headerValue != null) && (!(headerValue instanceof Byte))) {
486                         throw new IllegalArgumentException("ByteUser Defined must be a Byte");
487                     }
488                     mByteUserDefined[headerID - 0xB0] = (Byte)headerValue;
489 
490                     break;
491                 }
492                 // Verify that is was not the 4 byte unsigned integer user
493                 // defined header
494                 if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
495                     if (!(headerValue instanceof Long)) {
496                         if (headerValue == null) {
497                             mIntegerUserDefined[headerID - 0xF0] = null;
498                             break;
499                         }
500                         throw new IllegalArgumentException("Integer User Defined must be a Long");
501                     }
502                     temp = ((Long)headerValue).longValue();
503                     if ((temp < 0L) || (temp > 0xFFFFFFFFL)) {
504                         throw new IllegalArgumentException(
505                                 "Integer User Defined must be between 0 and 0xFFFFFFFF");
506                     }
507                     mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue;
508                     break;
509                 }
510                 throw new IllegalArgumentException("Invalid Header Identifier");
511         }
512     }
513 
514     /**
515      * Retrieves the value of the header identifier provided. The type of the
516      * Object returned is defined in the description of this interface.
517      * @param headerID the header identifier whose value is to be returned
518      * @return the value of the header provided or <code>null</code> if the
519      *         header identifier specified is not part of this
520      *         <code>HeaderSet</code> object
521      * @throws IllegalArgumentException if the <code>headerID</code> is not one
522      *         defined in this interface or any of the user-defined headers
523      * @throws IOException if an error occurred in the transport layer during
524      *         the operation or if the connection has been closed
525      */
getHeader(int headerID)526     public Object getHeader(int headerID) throws IOException {
527 
528         switch (headerID) {
529             case COUNT:
530                 return mCount;
531             case NAME:
532                 return mName;
533             case TYPE:
534                 return mType;
535             case LENGTH:
536                 return mLength;
537             case TIME_ISO_8601:
538                 return mIsoTime;
539             case TIME_4_BYTE:
540                 return mByteTime;
541             case DESCRIPTION:
542                 return mDescription;
543             case TARGET:
544                 return mTarget;
545             case HTTP:
546                 return mHttpHeader;
547             case WHO:
548                 return mWho;
549             case CONNECTION_ID:
550                 return mConnectionID;
551             case OBJECT_CLASS:
552                 return mObjectClass;
553             case APPLICATION_PARAMETER:
554                 return mAppParam;
555             case SINGLE_RESPONSE_MODE:
556                 return mSingleResponseMode;
557             case SINGLE_RESPONSE_MODE_PARAMETER:
558                 return mSrmParam;
559             default:
560                 // Verify that it was not a Unicode String user Defined
561                 if ((headerID >= 0x30) && (headerID <= 0x3F)) {
562                     return mUnicodeUserDefined[headerID - 0x30];
563                 }
564                 // Verify that it was not a byte sequence user defined header
565                 if ((headerID >= 0x70) && (headerID <= 0x7F)) {
566                     return mSequenceUserDefined[headerID - 0x70];
567                 }
568                 // Verify that it was not a byte user defined header
569                 if ((headerID >= 0xB0) && (headerID <= 0xBF)) {
570                     return mByteUserDefined[headerID - 0xB0];
571                 }
572                 // Verify that it was not a integer user defined header
573                 if ((headerID >= 0xF0) && (headerID <= 0xFF)) {
574                     return mIntegerUserDefined[headerID - 0xF0];
575                 }
576                 throw new IllegalArgumentException("Invalid Header Identifier");
577         }
578     }
579 
580     /**
581      * Retrieves the list of headers that may be retrieved via the
582      * <code>getHeader</code> method that will not return <code>null</code>. In
583      * other words, this method returns all the headers that are available in
584      * this object.
585      * @see #getHeader
586      * @return the array of headers that are set in this object or
587      *         <code>null</code> if no headers are available
588      * @throws IOException if an error occurred in the transport layer during
589      *         the operation or the connection has been closed
590      *
591      * @hide
592      */
getHeaderList()593     public int[] getHeaderList() throws IOException {
594         ByteArrayOutputStream out = new ByteArrayOutputStream();
595 
596         if (mCount != null) {
597             out.write(COUNT);
598         }
599         if (mName != null) {
600             out.write(NAME);
601         }
602         if (mType != null) {
603             out.write(TYPE);
604         }
605         if (mLength != null) {
606             out.write(LENGTH);
607         }
608         if (mIsoTime != null) {
609             out.write(TIME_ISO_8601);
610         }
611         if (mByteTime != null) {
612             out.write(TIME_4_BYTE);
613         }
614         if (mDescription != null) {
615             out.write(DESCRIPTION);
616         }
617         if (mTarget != null) {
618             out.write(TARGET);
619         }
620         if (mHttpHeader != null) {
621             out.write(HTTP);
622         }
623         if (mWho != null) {
624             out.write(WHO);
625         }
626         if (mAppParam != null) {
627             out.write(APPLICATION_PARAMETER);
628         }
629         if (mObjectClass != null) {
630             out.write(OBJECT_CLASS);
631         }
632         if(mSingleResponseMode != null) {
633             out.write(SINGLE_RESPONSE_MODE);
634         }
635         if(mSrmParam != null) {
636             out.write(SINGLE_RESPONSE_MODE_PARAMETER);
637         }
638 
639         for (int i = 0x30; i < 0x40; i++) {
640             if (mUnicodeUserDefined[i - 0x30] != null) {
641                 out.write(i);
642             }
643         }
644 
645         for (int i = 0x70; i < 0x80; i++) {
646             if (mSequenceUserDefined[i - 0x70] != null) {
647                 out.write(i);
648             }
649         }
650 
651         for (int i = 0xB0; i < 0xC0; i++) {
652             if (mByteUserDefined[i - 0xB0] != null) {
653                 out.write(i);
654             }
655         }
656 
657         for (int i = 0xF0; i < 0x100; i++) {
658             if (mIntegerUserDefined[i - 0xF0] != null) {
659                 out.write(i);
660             }
661         }
662 
663         byte[] headers = out.toByteArray();
664         out.close();
665 
666         if ((headers == null) || (headers.length == 0)) {
667             return null;
668         }
669 
670         int[] result = new int[headers.length];
671         for (int i = 0; i < headers.length; i++) {
672             // Convert the byte to a positive integer.  That is, an integer
673             // between 0 and 256.
674             result[i] = headers[i] & 0xFF;
675         }
676 
677         return result;
678     }
679 
680     /**
681      * Sets the authentication challenge header. The <code>realm</code> will be
682      * encoded based upon the default encoding scheme used by the implementation
683      * to encode strings. Therefore, the encoding scheme used to encode the
684      * <code>realm</code> is application dependent.
685      * @param realm a short description that describes what password to use; if
686      *        <code>null</code> no realm will be sent in the authentication
687      *        challenge header
688      * @param userID if <code>true</code>, a user ID is required in the reply;
689      *        if <code>false</code>, no user ID is required
690      * @param access if <code>true</code> then full access will be granted if
691      *        successful; if <code>false</code> then read-only access will be
692      *        granted if successful
693      * @throws IOException
694      *
695      * @hide
696      */
createAuthenticationChallenge(String realm, boolean userID, boolean access)697     public void createAuthenticationChallenge(String realm, boolean userID, boolean access)
698             throws IOException {
699 
700         nonce = new byte[16];
701         if(mRandom == null) {
702             mRandom = new SecureRandom();
703         }
704         for (int i = 0; i < 16; i++) {
705             nonce[i] = (byte)mRandom.nextInt();
706         }
707 
708         mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID);
709     }
710 
711     /**
712      * Returns the response code received from the server. Response codes are
713      * defined in the <code>ResponseCodes</code> class.
714      * @see ResponseCodes
715      * @return the response code retrieved from the server
716      * @throws IOException if an error occurred in the transport layer during
717      *         the transaction; if this method is called on a
718      *         <code>HeaderSet</code> object created by calling
719      *         <code>createHeaderSet()</code> in a <code>ClientSession</code>
720      *         object; if this object was created by an OBEX server
721      */
getResponseCode()722     public int getResponseCode() throws IOException {
723         if (responseCode == -1) {
724             throw new IOException("May not be called on a server");
725         } else {
726             return responseCode;
727         }
728     }
729 
730     @Override
toString()731     public String toString() {
732         return "HeaderSet " + System.identityHashCode(this) + ": NAME=" + mName;
733     }
734 
dump()735     public String dump() {
736         return "Dumping HeaderSet " + this
737             + "\n\tCONNECTION_ID : " + Arrays.toString(mConnectionID)
738             + "\n\tNAME : " + mName
739             + "\n\tTYPE : " + mType
740             + "\n\tTARGET : " + Arrays.toString(mTarget)
741             + "\n\tWHO : " + Arrays.toString(mWho)
742             + "\n\tAPPLICATION_PARAMETER : " + Arrays.toString(mAppParam)
743             + "\n\tDumping HeaderSet END";
744     }
745 }
746