public int getHeaderLength() {
    long id = mListener.getConnectionId();
    if (id == -1) {
      replyHeader.mConnectionID = null;
    } else {
      replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
    }

    byte[] headerArray = ObexHelper.createHeader(replyHeader, false);

    return headerArray.length;
  }
  /**
   * Specifies the headers that should be sent in the next OBEX message that is sent.
   *
   * @param headers the headers to send in the next message
   * @throws IOException if this <code>Operation</code> has been closed or the transaction has ended
   *     and no further messages will be exchanged
   * @throws IllegalArgumentException if <code>headers</code> was not created by a call to <code>
   *     ServerRequestHandler.createHeaderSet()</code>
   */
  public void sendHeaders(HeaderSet headers) throws IOException {
    ensureOpen();

    if (headers == null) {
      throw new IOException("Headers may not be null");
    }

    int[] headerList = headers.getHeaderList();
    if (headerList != null) {
      for (int i = 0; i < headerList.length; i++) {
        replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
      }
    }
  }
 /**
  * Returns the type of content that the resource connected to is providing. E.g. if the connection
  * is via HTTP, then the value of the content-type header field is returned.
  *
  * @return the content type of the resource that the URL references, or <code>null</code> if not
  *     known
  */
 public String getType() {
   try {
     return (String) requestHeader.getHeader(HeaderSet.TYPE);
   } catch (IOException e) {
     return null;
   }
 }
  /**
   * Returns the length of the content which is being provided. E.g. if the connection is via HTTP,
   * then the value of the content-length header field is returned.
   *
   * @return the content length of the resource that this connection's URL references, or -1 if the
   *     content length is not known
   */
  public long getLength() {
    try {
      Long temp = (Long) requestHeader.getHeader(HeaderSet.LENGTH);

      if (temp == null) {
        return -1;
      } else {
        return temp.longValue();
      }
    } catch (IOException e) {
      return -1;
    }
  }
  /**
   * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it will wait for a response
   * from the client before ending.
   *
   * @param type the response code to send back to the client
   * @return <code>true</code> if the final bit was not set on the reply; <code>false</code> if no
   *     reply was received because the operation ended, an abort was received, or the final bit was
   *     set in the reply
   * @throws IOException if an IO error occurs
   */
  public synchronized boolean sendReply(int type) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int bytesReceived;

    long id = mListener.getConnectionId();
    if (id == -1) {
      replyHeader.mConnectionID = null;
    } else {
      replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
    }

    byte[] headerArray = ObexHelper.createHeader(replyHeader, true);
    int bodyLength = -1;
    int orginalBodyLength = -1;

    if (mPrivateOutput != null) {
      bodyLength = mPrivateOutput.size();
      orginalBodyLength = bodyLength;
    }

    if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {

      int end = 0;
      int start = 0;

      while (end != headerArray.length) {
        end =
            ObexHelper.findHeaderEnd(
                headerArray, start, mMaxPacketLength - ObexHelper.BASE_PACKET_LENGTH);
        if (end == -1) {

          mClosed = true;

          if (mPrivateInput != null) {
            mPrivateInput.close();
          }

          if (mPrivateOutput != null) {
            mPrivateOutput.close();
          }
          mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
          throw new IOException("OBEX Packet exceeds max packet size");
        }
        byte[] sendHeader = new byte[end - start];
        System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);

        mParent.sendResponse(type, sendHeader);
        start = end;
      }

      if (bodyLength > 0) {
        return true;
      } else {
        return false;
      }

    } else {
      out.write(headerArray);
    }

    // For Get operation: if response code is OBEX_HTTP_OK, then this is the
    // last packet; so set finalBitSet to true.
    if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) {
      finalBitSet = true;
    }

    if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
      if (bodyLength > 0) {
        /*
         * Determine if I can send the whole body or just part of
         * the body.  Remember that there is the 3 bytes for the
         * response message and 3 bytes for the header ID and length
         */
        if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
          bodyLength = mMaxPacketLength - headerArray.length - 6;
        }

        byte[] body = mPrivateOutput.readBytes(bodyLength);

        /*
         * Since this is a put request if the final bit is set or
         * the output stream is closed we need to send the 0x49
         * (End of Body) otherwise, we need to send 0x48 (Body)
         */
        if ((finalBitSet) || (mPrivateOutput.isClosed())) {
          out.write(0x49);
        } else {
          out.write(0x48);
        }

        bodyLength += 3;
        out.write((byte) (bodyLength >> 8));
        out.write((byte) bodyLength);
        out.write(body);
      }
    }

    if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
      out.write(0x49);
      orginalBodyLength = 3;
      out.write((byte) (orginalBodyLength >> 8));
      out.write((byte) orginalBodyLength);
    }

    mResponseSize = 3;
    mParent.sendResponse(type, out.toByteArray());

    if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
      int headerID = mInput.read();
      int length = mInput.read();
      length = (length << 8) + mInput.read();
      if ((headerID != ObexHelper.OBEX_OPCODE_PUT)
          && (headerID != ObexHelper.OBEX_OPCODE_PUT_FINAL)
          && (headerID != ObexHelper.OBEX_OPCODE_GET)
          && (headerID != ObexHelper.OBEX_OPCODE_GET_FINAL)) {

        if (length > 3) {
          byte[] temp = new byte[length - 3];
          // First three bytes already read, compensating for this
          bytesReceived = mInput.read(temp);

          while (bytesReceived != temp.length) {
            bytesReceived += mInput.read(temp, bytesReceived, temp.length - bytesReceived);
          }
        }

        /*
         * Determine if an ABORT was sent as the reply
         */
        if (headerID == ObexHelper.OBEX_OPCODE_ABORT) {
          mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
          mClosed = true;
          isAborted = true;
          mExceptionString = "Abort Received";
          throw new IOException("Abort Received");
        } else {
          mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
          mClosed = true;
          mExceptionString = "Bad Request Received";
          throw new IOException("Bad Request Received");
        }
      } else {

        if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
          finalBitSet = true;
        } else if (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL) {
          mRequestFinished = true;
        }

        /*
         * Determine if the packet length is larger then this device can receive
         */
        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
          mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
          throw new IOException("Packet received was too large");
        }

        /*
         * Determine if any headers were sent in the initial request
         */
        if (length > 3) {
          byte[] data = new byte[length - 3];
          bytesReceived = mInput.read(data);

          while (bytesReceived != data.length) {
            bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
          }
          byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);
          if (body != null) {
            mHasBody = true;
          }
          if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
            mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
          } else {
            mListener.setConnectionId(1);
          }

          if (requestHeader.mAuthResp != null) {
            if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
              mExceptionString = "Authentication Failed";
              mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
              mClosed = true;
              requestHeader.mAuthResp = null;
              return false;
            }
            requestHeader.mAuthResp = null;
          }

          if (requestHeader.mAuthChall != null) {
            mParent.handleAuthChall(requestHeader);
            // send the auhtResp to the client
            replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
            System.arraycopy(
                requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0, replyHeader.mAuthResp.length);
            requestHeader.mAuthResp = null;
            requestHeader.mAuthChall = null;
          }

          if (body != null) {
            mPrivateInput.writeBytes(body, 1);
          }
        }
      }
      return true;
    } else {
      return false;
    }
  }
  /**
   * Creates new ServerOperation
   *
   * @param p the parent that created this object
   * @param in the input stream to read from
   * @param out the output stream to write to
   * @param request the initial request that was received from the client
   * @param maxSize the max packet size that the client will accept
   * @param listen the listener that is responding to the request
   * @throws IOException if an IO error occurs
   */
  public ServerOperation(
      ServerSession p, InputStream in, int request, int maxSize, ServerRequestHandler listen)
      throws IOException {

    isAborted = false;
    mParent = p;
    mInput = in;
    mMaxPacketLength = maxSize;
    mClosed = false;
    requestHeader = new HeaderSet();
    replyHeader = new HeaderSet();
    mPrivateInput = new PrivateInputStream(this);
    mResponseSize = 3;
    mListener = listen;
    mRequestFinished = false;
    mPrivateOutputOpen = false;
    mHasBody = false;
    int bytesReceived;

    /*
     * Determine if this is a PUT request
     */
    if ((request == 0x02) || (request == 0x82)) {
      /*
       * It is a PUT request.
       */
      mGetOperation = false;

      /*
       * Determine if the final bit is set
       */
      if ((request & 0x80) == 0) {
        finalBitSet = false;
      } else {
        finalBitSet = true;
        mRequestFinished = true;
      }
    } else if ((request == 0x03) || (request == 0x83)) {
      /*
       * It is a GET request.
       */
      mGetOperation = true;

      // For Get request, final bit set is decided by server side logic
      finalBitSet = false;

      if (request == 0x83) {
        mRequestFinished = true;
      }
    } else {
      throw new IOException("ServerOperation can not handle such request");
    }

    int length = in.read();
    length = (length << 8) + in.read();

    /*
     * Determine if the packet length is larger than this device can receive
     */
    if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
      mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
      throw new IOException("Packet received was too large");
    }

    /*
     * Determine if any headers were sent in the initial request
     */
    if (length > 3) {
      byte[] data = new byte[length - 3];
      bytesReceived = in.read(data);

      while (bytesReceived != data.length) {
        bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived);
      }

      byte[] body = ObexHelper.updateHeaderSet(requestHeader, data);

      if (body != null) {
        mHasBody = true;
      }

      if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
        mListener.setConnectionId(ObexHelper.convertToLong(requestHeader.mConnectionID));
      } else {
        mListener.setConnectionId(1);
      }

      if (requestHeader.mAuthResp != null) {
        if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
          mExceptionString = "Authentication Failed";
          mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
          mClosed = true;
          requestHeader.mAuthResp = null;
          return;
        }
      }

      if (requestHeader.mAuthChall != null) {
        mParent.handleAuthChall(requestHeader);
        // send the  authResp to the client
        replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
        System.arraycopy(
            requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0, replyHeader.mAuthResp.length);
        requestHeader.mAuthResp = null;
        requestHeader.mAuthChall = null;
      }

      if (body != null) {
        mPrivateInput.writeBytes(body, 1);
      } else {
        while ((!mGetOperation) && (!finalBitSet)) {
          sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
          if (mPrivateInput.available() > 0) {
            break;
          }
        }
      }
    }

    while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
      sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
      if (mPrivateInput.available() > 0) {
        break;
      }
    }

    // wait for get request finished !!!!
    while (mGetOperation && !mRequestFinished) {
      sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
    }
  }
  /**
   * Handles a connect request from a client. This method will read the rest of the request from the
   * client. Assuming the request is valid, it will create a <code>HeaderSet</code> object to pass
   * to the <code>ServerRequestHandler</code> object. After the handler processes the request, this
   * method will create a reply message to send to the server with the response code provided.
   *
   * @throws IOException if an error occurred at the transport layer
   */
  private void handleConnectRequest() throws IOException {
    int packetLength;
    @SuppressWarnings("unused")
    int version;
    @SuppressWarnings("unused")
    int flags;
    int totalLength = 7;
    byte[] head = null;
    int code = -1;
    HeaderSet request = new HeaderSet();
    HeaderSet reply = new HeaderSet();

    /*
     * Read in the length of the OBEX packet, OBEX version, flags, and max
     * packet length
     */
    packetLength = mInput.read();
    packetLength = (packetLength << 8) + mInput.read();
    version = mInput.read();
    flags = mInput.read();
    mMaxPacketLength = mInput.read();
    mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();

    // should we check it?
    if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
      mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
    }

    if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
      code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
      totalLength = 7;
    } else {
      if (packetLength > 7) {
        mData.reset();
        mData.write(mInput, packetLength - 7);

        ObexHelper.updateHeaderSet(request, mData, null, mHeaderBuffer);
      }

      if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
        mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
      } else {
        mListener.setConnectionId(1);
      }

      if (request.mAuthResp != null) {
        if (!handleAuthResp(request.mAuthResp)) {
          code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
          mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte) 0x01, request.mAuthResp));
        }
        request.mAuthResp = null;
      }

      if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
        if (request.mAuthChall != null) {
          handleAuthChall(request);
          reply.mAuthResp = new byte[request.mAuthResp.length];
          System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0, reply.mAuthResp.length);
          request.mAuthChall = null;
          request.mAuthResp = null;
        }

        try {
          code = mListener.onConnect(request, reply);
          code = validateResponseCode(code);

          if (reply.nonce != null) {
            mChallengeDigest = new byte[16];
            System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
          } else {
            mChallengeDigest = null;
          }
          long id = mListener.getConnectionId();
          if (id == -1) {
            reply.mConnectionID = null;
          } else {
            reply.mConnectionID = ObexHelper.convertToByteArray(id);
          }

          head = ObexHelper.createHeader(reply, false);
          totalLength += head.length;

          if (totalLength > mMaxPacketLength) {
            totalLength = 7;
            head = null;
            code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
          }
        } catch (Exception e) {
          e.printStackTrace();
          totalLength = 7;
          head = null;
          code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
        }
      }
    }

    // Compute Length of OBEX CONNECT packet
    byte[] length = ObexHelper.convertToByteArray(totalLength);

    /*
     * Write the OBEX CONNECT packet to the server. Byte 0: response code
     * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
     * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
     * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
     */
    byte[] sendData = new byte[totalLength];
    sendData[0] = (byte) code;
    sendData[1] = length[2];
    sendData[2] = length[3];
    sendData[3] = (byte) 0x10;
    sendData[4] = (byte) 0x00;
    sendData[5] = (byte) (ObexHelper.MAX_PACKET_SIZE_INT >> 8);
    sendData[6] = (byte) (ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);

    if (head != null) {
      System.arraycopy(head, 0, sendData, 7, head.length);
    }

    mOutput.write(sendData);
    mOutput.flush();
  }
  /**
   * Handles a disconnect request from a client. This method will read the rest of the request from
   * the client. Assuming the request is valid, it will create a <code>HeaderSet</code> object to
   * pass to the <code>ServerRequestHandler</code> object. After the handler processes the request,
   * this method will create a reply message to send to the server.
   *
   * @throws IOException if an error occurred at the transport layer
   */
  private void handleDisconnectRequest() throws IOException {
    int length;
    int code = ResponseCodes.OBEX_HTTP_OK;
    int totalLength = 3;
    byte[] head = null;
    HeaderSet request = new HeaderSet();
    HeaderSet reply = new HeaderSet();

    length = mInput.read();
    length = (length << 8) + mInput.read();

    if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
      code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
      totalLength = 3;
    } else {
      if (length > 3) {
        mData.reset();
        mData.write(mInput, length - 3);

        ObexHelper.updateHeaderSet(request, mData, null, mHeaderBuffer);
      }

      if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
        mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
      } else {
        mListener.setConnectionId(1);
      }

      if (request.mAuthResp != null) {
        if (!handleAuthResp(request.mAuthResp)) {
          code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
          mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte) 0x01, request.mAuthResp));
        }
        request.mAuthResp = null;
      }

      if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {

        if (request.mAuthChall != null) {
          handleAuthChall(request);
          request.mAuthChall = null;
        }

        try {
          mListener.onDisconnect(request, reply);
        } catch (Exception e) {
          sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
          return;
        }

        long id = mListener.getConnectionId();
        if (id == -1) {
          reply.mConnectionID = null;
        } else {
          reply.mConnectionID = ObexHelper.convertToByteArray(id);
        }

        head = ObexHelper.createHeader(reply, false);
        totalLength += head.length;

        if (totalLength > mMaxPacketLength) {
          totalLength = 3;
          head = null;
          code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
        }
      }
    }

    // Compute Length of OBEX CONNECT packet
    mData.reset();
    mData.write((byte) code);
    mData.write((byte) (totalLength >> 8));
    mData.write((byte) totalLength);
    if (head != null) {
      mData.write(head);
    }
    /*
     * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
     * Byte 1&2: Connect Packet Length Byte 3 to n: headers
     */
    mData.read(mOutput);
    mOutput.flush();
  }
  /**
   * Handles a SETPATH request from a client. This method will read the rest of the request from the
   * client. Assuming the request is valid, it will create a <code>HeaderSet</code> object to pass
   * to the <code>ServerRequestHandler</code> object. After the handler processes the request, this
   * method will create a reply message to send to the server with the response code provided.
   *
   * @throws IOException if an error occurred at the transport layer
   */
  private void handleSetPathRequest() throws IOException {
    int length;
    int flags;
    @SuppressWarnings("unused")
    int constants;
    int totalLength = 3;
    byte[] head = null;
    int code = -1;
    HeaderSet request = new HeaderSet();
    HeaderSet reply = new HeaderSet();

    length = mInput.read();
    length = (length << 8) + mInput.read();
    flags = mInput.read();
    constants = mInput.read();

    if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
      code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
      totalLength = 3;
    } else {
      if (length > 5) {
        mData.reset();
        mData.write(mInput, length - 5);

        ObexHelper.updateHeaderSet(request, mData, null, mHeaderBuffer);

        if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
          mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
        } else {
          mListener.setConnectionId(1);
        }
        // the Auth chan is initiated by the server, client sent back the authResp .
        if (request.mAuthResp != null) {
          if (!handleAuthResp(request.mAuthResp)) {
            code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
            mListener.onAuthenticationFailure(
                ObexHelper.getTagValue((byte) 0x01, request.mAuthResp));
          }
          request.mAuthResp = null;
        }
      }

      if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
        // the Auth challenge is initiated by the client
        // the server will send back the authResp to the client
        if (request.mAuthChall != null) {
          handleAuthChall(request);
          reply.mAuthResp = new byte[request.mAuthResp.length];
          System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0, reply.mAuthResp.length);
          request.mAuthChall = null;
          request.mAuthResp = null;
        }
        boolean backup = false;
        boolean create = true;
        if (!((flags & 1) == 0)) {
          backup = true;
        }
        if (!((flags & 2) == 0)) {
          create = false;
        }

        try {
          code = mListener.onSetPath(request, reply, backup, create);
        } catch (Exception e) {
          sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
          return;
        }

        code = validateResponseCode(code);

        if (reply.nonce != null) {
          mChallengeDigest = new byte[16];
          System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
        } else {
          mChallengeDigest = null;
        }

        long id = mListener.getConnectionId();
        if (id == -1) {
          reply.mConnectionID = null;
        } else {
          reply.mConnectionID = ObexHelper.convertToByteArray(id);
        }

        head = ObexHelper.createHeader(reply, false);
        totalLength += head.length;

        if (totalLength > mMaxPacketLength) {
          totalLength = 3;
          head = null;
          code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
        }
      }
    }

    // Compute Length of OBEX SETPATH packet
    mData.reset();
    mData.write((byte) code);
    mData.write((byte) (totalLength >> 8));
    mData.write((byte) totalLength);
    if (head != null) {
      mData.write(head);
    }
    /*
     * Write the OBEX SETPATH packet to the server. Byte 0: response code
     * Byte 1&2: Connect Packet Length Byte 3 to n: headers
     */
    mData.read(mOutput);
    mOutput.flush();
  }