Home | History | Annotate | Download | only in obex
      1 /*
      2  * Copyright (c) 2008-2009, Motorola, Inc.
      3  *
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are met:
      8  *
      9  * - Redistributions of source code must retain the above copyright notice,
     10  * this list of conditions and the following disclaimer.
     11  *
     12  * - Redistributions in binary form must reproduce the above copyright notice,
     13  * this list of conditions and the following disclaimer in the documentation
     14  * and/or other materials provided with the distribution.
     15  *
     16  * - Neither the name of the Motorola, Inc. nor the names of its contributors
     17  * may be used to endorse or promote products derived from this software
     18  * without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 package javax.obex;
     34 
     35 import java.io.IOException;
     36 import java.io.InputStream;
     37 import java.io.OutputStream;
     38 import java.io.DataInputStream;
     39 import java.io.DataOutputStream;
     40 import java.io.ByteArrayOutputStream;
     41 
     42 /**
     43  * This class implements the <code>Operation</code> interface. It will read and
     44  * write data via puts and gets.
     45  * @hide
     46  */
     47 public final class ClientOperation implements Operation, BaseStream {
     48 
     49     private ClientSession mParent;
     50 
     51     private boolean mInputOpen;
     52 
     53     private PrivateInputStream mPrivateInput;
     54 
     55     private boolean mPrivateInputOpen;
     56 
     57     private PrivateOutputStream mPrivateOutput;
     58 
     59     private boolean mPrivateOutputOpen;
     60 
     61     private String mExceptionMessage;
     62 
     63     private int mMaxPacketSize;
     64 
     65     private boolean mOperationDone;
     66 
     67     private boolean mGetOperation;
     68 
     69     private HeaderSet mRequestHeader;
     70 
     71     private HeaderSet mReplyHeader;
     72 
     73     private boolean mEndOfBodySent;
     74 
     75     /**
     76      * Creates new OperationImpl to read and write data to a server
     77      * @param maxSize the maximum packet size
     78      * @param p the parent to this object
     79      * @param type <code>true</code> if this is a get request;
     80      *        <code>false</code. if this is a put request
     81      * @param header the header to set in the initial request
     82      * @throws IOException if the an IO error occurred
     83      */
     84     public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
     85             throws IOException {
     86 
     87         mParent = p;
     88         mEndOfBodySent = false;
     89         mInputOpen = true;
     90         mOperationDone = false;
     91         mMaxPacketSize = maxSize;
     92         mGetOperation = type;
     93 
     94         mPrivateInputOpen = false;
     95         mPrivateOutputOpen = false;
     96         mPrivateInput = null;
     97         mPrivateOutput = null;
     98 
     99         mReplyHeader = new HeaderSet();
    100 
    101         mRequestHeader = new HeaderSet();
    102 
    103         int[] headerList = header.getHeaderList();
    104 
    105         if (headerList != null) {
    106 
    107             for (int i = 0; i < headerList.length; i++) {
    108                 mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
    109             }
    110         }
    111 
    112         if ((header).mAuthChall != null) {
    113             mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
    114             System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
    115                     (header).mAuthChall.length);
    116         }
    117 
    118         if ((header).mAuthResp != null) {
    119             mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
    120             System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
    121                     (header).mAuthResp.length);
    122 
    123         }
    124     }
    125 
    126     /**
    127      * Sends an ABORT message to the server. By calling this method, the
    128      * corresponding input and output streams will be closed along with this
    129      * object.
    130      * @throws IOException if the transaction has already ended or if an OBEX
    131      *         server called this method
    132      */
    133     public synchronized void abort() throws IOException {
    134         ensureOpen();
    135         //no compatible with sun-ri
    136         if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
    137             throw new IOException("Operation has already ended");
    138         }
    139 
    140         mExceptionMessage = "Operation aborted";
    141         if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    142             mOperationDone = true;
    143             /*
    144              * Since we are not sending any headers or returning any headers then
    145              * we just need to write and read the same bytes
    146              */
    147             mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
    148 
    149             if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
    150                 throw new IOException("Invalid response code from server");
    151             }
    152 
    153             mExceptionMessage = null;
    154         }
    155 
    156         close();
    157     }
    158 
    159     /**
    160      * Retrieves the response code retrieved from the server. Response codes are
    161      * defined in the <code>ResponseCodes</code> interface.
    162      * @return the response code retrieved from the server
    163      * @throws IOException if an error occurred in the transport layer during
    164      *         the transaction; if this method is called on a
    165      *         <code>HeaderSet</code> object created by calling
    166      *         <code>createHeaderSet</code> in a <code>ClientSession</code>
    167      *         object
    168      */
    169     public synchronized int getResponseCode() throws IOException {
    170         //avoid dup validateConnection
    171         if ((mReplyHeader.responseCode == -1)
    172                 || (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    173             validateConnection();
    174         }
    175 
    176         return mReplyHeader.responseCode;
    177     }
    178 
    179     /**
    180      * This method will always return <code>null</code>
    181      * @return <code>null</code>
    182      */
    183     public String getEncoding() {
    184         return null;
    185     }
    186 
    187     /**
    188      * Returns the type of content that the resource connected to is providing.
    189      * E.g. if the connection is via HTTP, then the value of the content-type
    190      * header field is returned.
    191      * @return the content type of the resource that the URL references, or
    192      *         <code>null</code> if not known
    193      */
    194     public String getType() {
    195         try {
    196             return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
    197         } catch (IOException e) {
    198             return null;
    199         }
    200     }
    201 
    202     /**
    203      * Returns the length of the content which is being provided. E.g. if the
    204      * connection is via HTTP, then the value of the content-length header field
    205      * is returned.
    206      * @return the content length of the resource that this connection's URL
    207      *         references, or -1 if the content length is not known
    208      */
    209     public long getLength() {
    210         try {
    211             Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
    212 
    213             if (temp == null) {
    214                 return -1;
    215             } else {
    216                 return temp.longValue();
    217             }
    218         } catch (IOException e) {
    219             return -1;
    220         }
    221     }
    222 
    223     /**
    224      * Open and return an input stream for a connection.
    225      * @return an input stream
    226      * @throws IOException if an I/O error occurs
    227      */
    228     public InputStream openInputStream() throws IOException {
    229 
    230         ensureOpen();
    231 
    232         if (mPrivateInputOpen)
    233             throw new IOException("no more input streams available");
    234         if (mGetOperation) {
    235             // send the GET request here
    236             validateConnection();
    237         } else {
    238             if (mPrivateInput == null) {
    239                 mPrivateInput = new PrivateInputStream(this);
    240             }
    241         }
    242 
    243         mPrivateInputOpen = true;
    244 
    245         return mPrivateInput;
    246     }
    247 
    248     /**
    249      * Open and return a data input stream for a connection.
    250      * @return an input stream
    251      * @throws IOException if an I/O error occurs
    252      */
    253     public DataInputStream openDataInputStream() throws IOException {
    254         return new DataInputStream(openInputStream());
    255     }
    256 
    257     /**
    258      * Open and return an output stream for a connection.
    259      * @return an output stream
    260      * @throws IOException if an I/O error occurs
    261      */
    262     public OutputStream openOutputStream() throws IOException {
    263 
    264         ensureOpen();
    265         ensureNotDone();
    266 
    267         if (mPrivateOutputOpen)
    268             throw new IOException("no more output streams available");
    269 
    270         if (mPrivateOutput == null) {
    271             // there are 3 bytes operation headers and 3 bytes body headers //
    272             mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
    273         }
    274 
    275         mPrivateOutputOpen = true;
    276 
    277         return mPrivateOutput;
    278     }
    279 
    280     public int getMaxPacketSize() {
    281         return mMaxPacketSize - 6 - getHeaderLength();
    282     }
    283 
    284     public int getHeaderLength() {
    285         // OPP may need it
    286         byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
    287         return headerArray.length;
    288     }
    289 
    290     /**
    291      * Open and return a data output stream for a connection.
    292      * @return an output stream
    293      * @throws IOException if an I/O error occurs
    294      */
    295     public DataOutputStream openDataOutputStream() throws IOException {
    296         return new DataOutputStream(openOutputStream());
    297     }
    298 
    299     /**
    300      * Closes the connection and ends the transaction
    301      * @throws IOException if the operation has already ended or is closed
    302      */
    303     public void close() throws IOException {
    304         mInputOpen = false;
    305         mPrivateInputOpen = false;
    306         mPrivateOutputOpen = false;
    307         mParent.setRequestInactive();
    308     }
    309 
    310     /**
    311      * Returns the headers that have been received during the operation.
    312      * Modifying the object returned has no effect on the headers that are sent
    313      * or retrieved.
    314      * @return the headers received during this <code>Operation</code>
    315      * @throws IOException if this <code>Operation</code> has been closed
    316      */
    317     public HeaderSet getReceivedHeader() throws IOException {
    318         ensureOpen();
    319 
    320         return mReplyHeader;
    321     }
    322 
    323     /**
    324      * Specifies the headers that should be sent in the next OBEX message that
    325      * is sent.
    326      * @param headers the headers to send in the next message
    327      * @throws IOException if this <code>Operation</code> has been closed or the
    328      *         transaction has ended and no further messages will be exchanged
    329      * @throws IllegalArgumentException if <code>headers</code> was not created
    330      *         by a call to <code>ServerRequestHandler.createHeaderSet()</code>
    331      * @throws NullPointerException if <code>headers</code> is <code>null</code>
    332      */
    333     public void sendHeaders(HeaderSet headers) throws IOException {
    334         ensureOpen();
    335         if (mOperationDone) {
    336             throw new IOException("Operation has already exchanged all data");
    337         }
    338 
    339         if (headers == null) {
    340             throw new IOException("Headers may not be null");
    341         }
    342 
    343         int[] headerList = headers.getHeaderList();
    344         if (headerList != null) {
    345             for (int i = 0; i < headerList.length; i++) {
    346                 mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
    347             }
    348         }
    349     }
    350 
    351     /**
    352      * Verifies that additional information may be sent. In other words, the
    353      * operation is not done.
    354      * @throws IOException if the operation is completed
    355      */
    356     public void ensureNotDone() throws IOException {
    357         if (mOperationDone) {
    358             throw new IOException("Operation has completed");
    359         }
    360     }
    361 
    362     /**
    363      * Verifies that the connection is open and no exceptions should be thrown.
    364      * @throws IOException if an exception needs to be thrown
    365      */
    366     public void ensureOpen() throws IOException {
    367         mParent.ensureOpen();
    368 
    369         if (mExceptionMessage != null) {
    370             throw new IOException(mExceptionMessage);
    371         }
    372         if (!mInputOpen) {
    373             throw new IOException("Operation has already ended");
    374         }
    375     }
    376 
    377     /**
    378      * Verifies that the connection is open and the proper data has been read.
    379      * @throws IOException if an IO error occurs
    380      */
    381     private void validateConnection() throws IOException {
    382         ensureOpen();
    383 
    384         // to sure only one privateInput object exist.
    385         if (mPrivateInput == null) {
    386             startProcessing();
    387         }
    388     }
    389 
    390     /**
    391      * Sends a request to the client of the specified type
    392      * @param opCode the request code to send to the client
    393      * @return <code>true</code> if there is more data to send;
    394      *         <code>false</code> if there is no more data to send
    395      * @throws IOException if an IO error occurs
    396      */
    397     private boolean sendRequest(int opCode) throws IOException {
    398         boolean returnValue = false;
    399         ByteArrayOutputStream out = new ByteArrayOutputStream();
    400         int bodyLength = -1;
    401         byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
    402         if (mPrivateOutput != null) {
    403             bodyLength = mPrivateOutput.size();
    404         }
    405 
    406         /*
    407          * Determine if there is space to add a body request.  At present
    408          * this method checks to see if there is room for at least a 17
    409          * byte body header.  This number needs to be at least 6 so that
    410          * there is room for the header ID and length and the reply ID and
    411          * length, but it is a waste of resources if we can't send much of
    412          * the body.
    413          */
    414         if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
    415             int end = 0;
    416             int start = 0;
    417             // split & send the headerArray in multiple packets.
    418 
    419             while (end != headerArray.length) {
    420                 //split the headerArray
    421                 end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
    422                         - ObexHelper.BASE_PACKET_LENGTH);
    423                 // can not split
    424                 if (end == -1) {
    425                     mOperationDone = true;
    426                     abort();
    427                     mExceptionMessage = "Header larger then can be sent in a packet";
    428                     mInputOpen = false;
    429 
    430                     if (mPrivateInput != null) {
    431                         mPrivateInput.close();
    432                     }
    433 
    434                     if (mPrivateOutput != null) {
    435                         mPrivateOutput.close();
    436                     }
    437                     throw new IOException("OBEX Packet exceeds max packet size");
    438                 }
    439 
    440                 byte[] sendHeader = new byte[end - start];
    441                 System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
    442                 if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput)) {
    443                     return false;
    444                 }
    445 
    446                 if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
    447                     return false;
    448                 }
    449 
    450                 start = end;
    451             }
    452 
    453             if (bodyLength > 0) {
    454                 return true;
    455             } else {
    456                 return false;
    457             }
    458         } else {
    459             out.write(headerArray);
    460         }
    461 
    462         if (bodyLength > 0) {
    463             /*
    464              * Determine if we can send the whole body or just part of
    465              * the body.  Remember that there is the 3 bytes for the
    466              * response message and 3 bytes for the header ID and length
    467              */
    468             if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
    469                 returnValue = true;
    470 
    471                 bodyLength = mMaxPacketSize - headerArray.length - 6;
    472             }
    473 
    474             byte[] body = mPrivateOutput.readBytes(bodyLength);
    475 
    476             /*
    477              * Since this is a put request if the final bit is set or
    478              * the output stream is closed we need to send the 0x49
    479              * (End of Body) otherwise, we need to send 0x48 (Body)
    480              */
    481             if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
    482                     && ((opCode & 0x80) != 0)) {
    483                 out.write(0x49);
    484                 mEndOfBodySent = true;
    485             } else {
    486                 out.write(0x48);
    487             }
    488 
    489             bodyLength += 3;
    490             out.write((byte)(bodyLength >> 8));
    491             out.write((byte)bodyLength);
    492 
    493             if (body != null) {
    494                 out.write(body);
    495             }
    496         }
    497 
    498         if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
    499             // only 0x82 or 0x83 can send 0x49
    500             if ((opCode & 0x80) == 0) {
    501                 out.write(0x48);
    502             } else {
    503                 out.write(0x49);
    504                 mEndOfBodySent = true;
    505 
    506             }
    507 
    508             bodyLength = 3;
    509             out.write((byte)(bodyLength >> 8));
    510             out.write((byte)bodyLength);
    511         }
    512 
    513         if (out.size() == 0) {
    514             if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput)) {
    515                 return false;
    516             }
    517             return returnValue;
    518         }
    519         if ((out.size() > 0)
    520                 && (!mParent.sendRequest(opCode, out.toByteArray(), mReplyHeader, mPrivateInput))) {
    521             return false;
    522         }
    523 
    524         // send all of the output data in 0x48,
    525         // send 0x49 with empty body
    526         if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
    527             returnValue = true;
    528 
    529         return returnValue;
    530     }
    531 
    532     /**
    533      * This method starts the processing thread results. It will send the
    534      * initial request. If the response takes more then one packet, a thread
    535      * will be started to handle additional requests
    536      * @throws IOException if an IO error occurs
    537      */
    538     private synchronized void startProcessing() throws IOException {
    539 
    540         if (mPrivateInput == null) {
    541             mPrivateInput = new PrivateInputStream(this);
    542         }
    543         boolean more = true;
    544 
    545         if (mGetOperation) {
    546             if (!mOperationDone) {
    547                 mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
    548                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    549                     more = sendRequest(0x03);
    550                 }
    551 
    552                 if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
    553                     mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
    554                 }
    555                 if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
    556                     mOperationDone = true;
    557                 }
    558             }
    559         } else {
    560 
    561             if (!mOperationDone) {
    562                 mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
    563                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    564                     more = sendRequest(0x02);
    565 
    566                 }
    567             }
    568 
    569             if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
    570                 mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
    571             }
    572 
    573             if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
    574                 mOperationDone = true;
    575             }
    576         }
    577     }
    578 
    579     /**
    580      * Continues the operation since there is no data to read.
    581      * @param sendEmpty <code>true</code> if the operation should send an empty
    582      *        packet or not send anything if there is no data to send
    583      * @param inStream <code>true</code> if the stream is input stream or is
    584      *        output stream
    585      * @throws IOException if an IO error occurs
    586      */
    587     public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
    588             throws IOException {
    589 
    590         if (mGetOperation) {
    591             if ((inStream) && (!mOperationDone)) {
    592                 // to deal with inputstream in get operation
    593                 mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
    594                 /*
    595                   * Determine if that was not the last packet in the operation
    596                   */
    597                 if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
    598                     mOperationDone = true;
    599                 }
    600 
    601                 return true;
    602 
    603             } else if ((!inStream) && (!mOperationDone)) {
    604                 // to deal with outputstream in get operation
    605 
    606                 if (mPrivateInput == null) {
    607                     mPrivateInput = new PrivateInputStream(this);
    608                 }
    609                 sendRequest(0x03);
    610                 return true;
    611 
    612             } else if (mOperationDone) {
    613                 return false;
    614             }
    615 
    616         } else {
    617             if ((!inStream) && (!mOperationDone)) {
    618                 // to deal with outputstream in put operation
    619                 if (mReplyHeader.responseCode == -1) {
    620                     mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
    621                 }
    622                 sendRequest(0x02);
    623                 return true;
    624             } else if ((inStream) && (!mOperationDone)) {
    625                 // How to deal with inputstream  in put operation ?
    626                 return false;
    627 
    628             } else if (mOperationDone) {
    629                 return false;
    630             }
    631 
    632         }
    633         return false;
    634     }
    635 
    636     /**
    637      * Called when the output or input stream is closed.
    638      * @param inStream <code>true</code> if the input stream is closed;
    639      *        <code>false</code> if the output stream is closed
    640      * @throws IOException if an IO error occurs
    641      */
    642     public void streamClosed(boolean inStream) throws IOException {
    643         if (!mGetOperation) {
    644             if ((!inStream) && (!mOperationDone)) {
    645                 // to deal with outputstream in put operation
    646 
    647                 boolean more = true;
    648 
    649                 if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
    650                     byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
    651                     if (headerArray.length <= 0)
    652                         more = false;
    653                 }
    654                 // If have not sent any data so send  all now
    655                 if (mReplyHeader.responseCode == -1) {
    656                     mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
    657                 }
    658 
    659                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    660                     more = sendRequest(0x02);
    661                 }
    662 
    663                 /*
    664                  * According to the IrOBEX specification, after the final put, you
    665                  * only have a single reply to send.  so we don't need the while
    666                  * loop.
    667                  */
    668                 while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
    669 
    670                     sendRequest(0x82);
    671                 }
    672                 mOperationDone = true;
    673             } else if ((inStream) && (mOperationDone)) {
    674                 // how to deal with input stream in put stream ?
    675                 mOperationDone = true;
    676             }
    677         } else {
    678             if ((inStream) && (!mOperationDone)) {
    679 
    680                 // to deal with inputstream in get operation
    681                 // Have not sent any data so send it all now
    682 
    683                 if (mReplyHeader.responseCode == -1) {
    684                     mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
    685                 }
    686 
    687                 while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
    688                     if (!sendRequest(0x83)) {
    689                         break;
    690                     }
    691                 }
    692                 while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
    693                     mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
    694                 }
    695                 mOperationDone = true;
    696             } else if ((!inStream) && (!mOperationDone)) {
    697                 // to deal with outputstream in get operation
    698                 // part of the data may have been sent in continueOperation.
    699 
    700                 boolean more = true;
    701 
    702                 if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
    703                     byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
    704                     if (headerArray.length <= 0)
    705                         more = false;
    706                 }
    707 
    708                 if (mPrivateInput == null) {
    709                     mPrivateInput = new PrivateInputStream(this);
    710                 }
    711                 if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
    712                     more = false;
    713 
    714                 mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
    715                 while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
    716                     more = sendRequest(0x03);
    717                 }
    718                 sendRequest(0x83);
    719                 //                parent.sendRequest(0x83, null, replyHeaders, privateInput);
    720                 if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
    721                     mOperationDone = true;
    722                 }
    723             }
    724         }
    725     }
    726 }
    727