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