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