1238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde/* Copyright (c) 2015 The Android Open Source Project
2238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Copyright (C) 2015 Samsung LSI
39439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * All rights reserved.
69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Redistribution and use in source and binary forms, with or without
89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * modification, are permitted provided that the following conditions are met:
99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions of source code must retain the above copyright notice,
119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer.
129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer in the documentation
159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * and/or other materials provided with the distribution.
169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * may be used to endorse or promote products derived from this software
199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * without specific prior written permission.
209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage javax.obex;
359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.IOException;
379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.InputStream;
389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.DataInputStream;
399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.OutputStream;
409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.DataOutputStream;
419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.ByteArrayOutputStream;
429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
43238e0f934f1f47263b384bc745ae0678c777130dCasper Bondeimport android.util.Log;
44238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * This class implements the Operation interface for server side connections.
479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * <P>
4805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <STRONG>Request Codes</STRONG> There are four different request codes that
4905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * are in this class. 0x02 is a PUT request that signals that the request is not
5005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * complete and requires an additional OBEX packet. 0x82 is a PUT request that
5105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * says that request is complete. In this case, the server can begin sending the
5205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * response. The 0x03 is a GET request that signals that the request is not
5305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * finished. When the server receives a 0x83, the client is signaling the server
5405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * that it is done with its request. TODO: Extend the ClientOperation and reuse
5505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * the methods defined TODO: in that class.
562e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide
579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic final class ServerOperation implements Operation, BaseStream {
599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
60238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private static final String TAG = "ServerOperation";
61238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
62238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private static final boolean V = ObexHelper.VDBG; // Verbose debugging
63238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public boolean isAborted;
659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public HeaderSet requestHeader;
679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public HeaderSet replyHeader;
699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public boolean finalBitSet;
719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
723998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private InputStream mInput;
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private ServerSession mParent;
759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
763998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private int mMaxPacketLength;
772e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly
783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private int mResponseSize;
799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mClosed;
819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mGetOperation;
839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private PrivateInputStream mPrivateInput;
859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private PrivateOutputStream mPrivateOutput;
879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
88238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private ObexTransport mTransport;
89238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mPrivateOutputOpen;
919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private String mExceptionString;
939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private ServerRequestHandler mListener;
959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mRequestFinished;
979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mHasBody;
999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
100fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    private boolean mSendBodyHeader = true;
101238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // Assume SRM disabled - needs to be explicit
102238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // enabled by client
103238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private boolean mSrmEnabled = false;
104238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // A latch - when triggered, there is not way back ;-)
105238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private boolean mSrmActive = false;
106238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // Set to true when a SRM enable response have been send
107238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private boolean mSrmResponseSent = false;
108238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // keep waiting until final-bit is received in request
109238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // to handle the case where the SRM enable header is in
110238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // a different OBEX packet than the SRMP header.
111238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private boolean mSrmWaitingForRemote = true;
112238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    // Why should we wait? - currently not exposed to apps.
113238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private boolean mSrmLocalWait = false;
114fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun     * Creates new ServerOperation
1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param p the parent that created this object
1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param in the input stream to read from
1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param out the output stream to write to
1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param request the initial request that was received from the client
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param maxSize the max packet size that the client will accept
1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param listen the listener that is responding to the request
1232e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an IO error occurs
1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public ServerOperation(ServerSession p, InputStream in, int request, int maxSize,
1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            ServerRequestHandler listen) throws IOException {
1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        isAborted = false;
1293998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mParent = p;
1303998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mInput = in;
1313998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mMaxPacketLength = maxSize;
1323998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mClosed = false;
1333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        requestHeader = new HeaderSet();
1343998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        replyHeader = new HeaderSet();
1353998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mPrivateInput = new PrivateInputStream(this);
1363998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mResponseSize = 3;
1373998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mListener = listen;
1383998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mRequestFinished = false;
1393998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mPrivateOutputOpen = false;
1403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mHasBody = false;
141238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        ObexPacket packet;
142238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        mTransport = p.getTransport();
1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Determine if this is a PUT request
1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
147238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if ((request == ObexHelper.OBEX_OPCODE_PUT) ||
148238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                (request == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
1499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /*
1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * It is a PUT request.
1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
1523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mGetOperation = false;
15365208317ba9d16486b47ebcaa868c596d424c87fLixin Yue
15465208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            /*
15565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue             * Determine if the final bit is set
15665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue             */
157238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if ((request & ObexHelper.OBEX_OPCODE_FINAL_BIT_MASK) == 0) {
15865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue                finalBitSet = false;
15965208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            } else {
16065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue                finalBitSet = true;
16165208317ba9d16486b47ebcaa868c596d424c87fLixin Yue                mRequestFinished = true;
16265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            }
163238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        } else if ((request == ObexHelper.OBEX_OPCODE_GET) ||
164238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                (request == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            /*
1669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             * It is a GET request.
1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly             */
1683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mGetOperation = true;
1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
17065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            // For Get request, final bit set is decided by server side logic
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            finalBitSet = false;
17265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue
173238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if (request == ObexHelper.OBEX_OPCODE_GET_FINAL) {
17465208317ba9d16486b47ebcaa868c596d424c87fLixin Yue                mRequestFinished = true;
17565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            }
1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
17765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            throw new IOException("ServerOperation can not handle such request");
1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
180238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        packet = ObexPacket.read(request, mInput);
1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Determine if the packet length is larger than this device can receive
1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
185238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
1863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
187238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            throw new IOException("Packet received was too large. Length: "
188238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    + packet.mLength + " maxLength: " + ObexHelper.getMaxRxPacketSize(mTransport));
1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Determine if any headers were sent in the initial request
1939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
194238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (packet.mLength > 3) {
195238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(!handleObexPacket(packet)) {
196238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                return;
1979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
198238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if (!mHasBody) {
1993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                while ((!mGetOperation) && (!finalBitSet)) {
2003998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
2013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    if (mPrivateInput.available() > 0) {
2029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
2053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            }
2063998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        }
2079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
2093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
2103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (mPrivateInput.available() > 0) {
2119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                break;
2129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // wait for get request finished !!!!
21665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        while (mGetOperation && !mRequestFinished) {
2173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
2189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
221238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    /**
222238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * Parse headers and update member variables
223238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @param packet the received obex packet
224238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @return false for failing authentication - and a OBEX_HTTP_UNAUTHORIZED
225238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * response have been send. Else true.
226238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @throws IOException
227238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     */
228238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private boolean handleObexPacket(ObexPacket packet) throws IOException {
229238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        byte[] body = updateRequestHeaders(packet);
230238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
231238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (body != null) {
232238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mHasBody = true;
233238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
234238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (mListener.getConnectionId() != -1 && requestHeader.mConnectionID != null) {
235238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mListener.setConnectionId(ObexHelper
236238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    .convertToLong(requestHeader.mConnectionID));
237238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        } else {
238238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mListener.setConnectionId(1);
239238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
240238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
241238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (requestHeader.mAuthResp != null) {
242238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if (!mParent.handleAuthResp(requestHeader.mAuthResp)) {
243238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mExceptionString = "Authentication Failed";
244238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mParent.sendResponse(ResponseCodes.OBEX_HTTP_UNAUTHORIZED, null);
245238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mClosed = true;
246238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                requestHeader.mAuthResp = null;
247238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                return false;
248238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            }
249238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            requestHeader.mAuthResp = null;
250238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
251238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
252238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (requestHeader.mAuthChall != null) {
253238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mParent.handleAuthChall(requestHeader);
254238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            // send the auhtResp to the client
255238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            replyHeader.mAuthResp = new byte[requestHeader.mAuthResp.length];
256238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            System.arraycopy(requestHeader.mAuthResp, 0, replyHeader.mAuthResp, 0,
257238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    replyHeader.mAuthResp.length);
258238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            requestHeader.mAuthResp = null;
259238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            requestHeader.mAuthChall = null;
260238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
261238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
262238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (body != null) {
263238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mPrivateInput.writeBytes(body, 1);
264238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
265238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        return true;
266238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    }
267238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
268238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    /**
269238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * Update the request header set, and sniff on SRM headers to update local state.
270238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @param data the OBEX packet data
271238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @return any bytes in a body/end-of-body header returned by {@link ObexHelper.updateHeaderSet}
272238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @throws IOException
273238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     */
274238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private byte[] updateRequestHeaders(ObexPacket packet) throws IOException {
275238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        byte[] body = null;
276238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (packet.mPayload != null) {
277238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            body = ObexHelper.updateHeaderSet(requestHeader, packet.mPayload);
278238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
279238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        Byte srmMode = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE);
280238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(mTransport.isSrmSupported() && srmMode != null
281238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                && srmMode == ObexHelper.OBEX_SRM_ENABLE) {
282238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mSrmEnabled = true;
283238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V) Log.d(TAG,"SRM is now ENABLED (but not active) for this operation");
284238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
285238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        checkForSrmWait(packet.mHeaderId);
286238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if((!mSrmWaitingForRemote) && (mSrmEnabled)) {
287238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V) Log.d(TAG,"SRM is now ACTIVE for this operation");
288238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mSrmActive = true;
289238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
290238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        return body;
291238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    }
292238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
293238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    /**
294238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * Call this only when a complete request have been received.
295238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * (This is not optimal, but the current design is not really suited to
296238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * the way SRM is specified.)
297238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     */
298238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private void checkForSrmWait(int headerId){
299238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (mSrmEnabled && (headerId == ObexHelper.OBEX_OPCODE_GET
300238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                || headerId == ObexHelper.OBEX_OPCODE_GET_FINAL
301238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                || headerId == ObexHelper.OBEX_OPCODE_PUT)) {
302238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            try {
303238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mSrmWaitingForRemote = false;
304238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                Byte srmp = (Byte)requestHeader.getHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER);
305238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                if(srmp != null && srmp == ObexHelper.OBEX_SRMP_WAIT) {
306238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    mSrmWaitingForRemote = true;
307238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    // Clear the wait header, as the absents of the header when the final bit is set
308238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    // indicates don't wait.
309238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    requestHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, null);
310238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                }
311238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            } catch (IOException e) {if(V){Log.w(TAG,"Exception while extracting header",e);}}
312238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
313238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    }
314238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
3153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public boolean isValidBody() {
3163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return mHasBody;
3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
3189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
32005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Determines if the operation should continue or should wait. If it should
32105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * continue, this method will continue the operation.
3229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param sendEmpty if <code>true</code> then this will continue the
32305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        operation even if no headers will be sent; if <code>false</code>
32405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        then this method will only continue the operation if there are
32505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        headers to send
32605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param inStream if<code>true</code> the stream is input stream, otherwise
32705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        output stream
3289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return <code>true</code> if the operation was completed;
32905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         <code>false</code> if no operation took place
3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
3329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throws IOException {
3333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (!mGetOperation) {
3349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (!finalBitSet) {
3359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (sendEmpty) {
3363998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
3379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    return true;
3389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
3393998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    if ((mResponseSize > 3) || (mPrivateOutput.size() > 0)) {
3403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
3419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        return true;
3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } else {
3439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        return false;
3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
3459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
3479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return false;
3489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
3503998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
3519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return true;
3529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
3539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
3549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
35605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Sends a reply to the client. If the reply is a OBEX_HTTP_CONTINUE, it
357238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * will wait for a response from the client before ending unless SRM is active.
3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param type the response code to send back to the client
3599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return <code>true</code> if the final bit was not set on the reply;
36005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         <code>false</code> if no reply was received because the operation
361238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *         ended, an abort was received, the final bit was set in the
362238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *         reply or SRM is active.
3632e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an IO error occurs
3649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3653998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public synchronized boolean sendReply(int type) throws IOException {
3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ByteArrayOutputStream out = new ByteArrayOutputStream();
367238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        boolean skipSend = false;
368238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        boolean skipReceive = false;
369238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        boolean srmRespSendPending = false;
3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3713998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        long id = mListener.getConnectionId();
3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (id == -1) {
3733998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            replyHeader.mConnectionID = null;
3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
3753998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
3769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
3779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
378238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(mSrmEnabled && !mSrmResponseSent) {
379238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            // As we are not ensured that the SRM enable is in the first OBEX packet
380238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            // We must check for each reply.
381238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V)Log.v(TAG, "mSrmEnabled==true, sending SRM enable response.");
382238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRM_ENABLE);
383238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            srmRespSendPending = true;
384238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
385238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
386238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(mSrmEnabled && !mGetOperation && mSrmLocalWait) {
387238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            replyHeader.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, (byte)ObexHelper.OBEX_SRMP_WAIT);
388238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
389238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
390238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        byte[] headerArray = ObexHelper.createHeader(replyHeader, true); // This clears the headers
3919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bodyLength = -1;
3929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int orginalBodyLength = -1;
3939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mPrivateOutput != null) {
3953998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            bodyLength = mPrivateOutput.size();
3969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            orginalBodyLength = bodyLength;
3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketLength) {
4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int end = 0;
4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int start = 0;
4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            while (end != headerArray.length) {
4053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketLength
4063998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        - ObexHelper.BASE_PACKET_LENGTH);
4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (end == -1) {
4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mClosed = true;
4109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    if (mPrivateInput != null) {
4123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        mPrivateInput.close();
4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    if (mPrivateOutput != null) {
4163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        mPrivateOutput.close();
4179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
4183998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mParent.sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    throw new IOException("OBEX Packet exceeds max packet size");
4209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] sendHeader = new byte[end - start];
4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
4239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4243998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                mParent.sendResponse(type, sendHeader);
4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                start = end;
4269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (bodyLength > 0) {
4299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return true;
4309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
4319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return false;
4329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
4359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            out.write(headerArray);
4369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
4379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
43865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        // For Get operation: if response code is OBEX_HTTP_OK, then this is the
43965208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        // last packet; so set finalBitSet to true.
44065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) {
44165208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            finalBitSet = true;
44265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        }
44365208317ba9d16486b47ebcaa868c596d424c87fLixin Yue
444238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(mSrmActive) {
445238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(!mGetOperation && type == ResponseCodes.OBEX_HTTP_CONTINUE &&
446238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    mSrmResponseSent == true) {
447238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // we are in the middle of a SRM PUT operation, don't send a continue.
448238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                skipSend = true;
449238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            } else if(mGetOperation && mRequestFinished == false && mSrmResponseSent == true) {
450238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // We are still receiving the get request, receive, but don't send continue.
451238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                skipSend = true;
452238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            } else if(mGetOperation && mRequestFinished == true) {
453238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // All done receiving the GET request, send data to the client, without
454238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // expecting a continue.
455238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                skipReceive = true;
456238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            }
457238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V)Log.v(TAG, "type==" + type + " skipSend==" + skipSend
458238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    + " skipReceive==" + skipReceive);
459238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
460238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(srmRespSendPending) {
461238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V)Log.v(TAG,
462238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    "SRM Enabled (srmRespSendPending == true)- sending SRM Enable response");
463238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mSrmResponseSent = true;
464238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
465238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
4663998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (bodyLength > 0) {
4689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * Determine if I can send the whole body or just part of
4709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * the body.  Remember that there is the 3 bytes for the
4719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * response message and 3 bytes for the header ID and length
4729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
4733998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (bodyLength > (mMaxPacketLength - headerArray.length - 6)) {
4743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    bodyLength = mMaxPacketLength - headerArray.length - 6;
4759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                byte[] body = mPrivateOutput.readBytes(bodyLength);
4789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * Since this is a put request if the final bit is set or
4819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * the output stream is closed we need to send the 0x49
4829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * (End of Body) otherwise, we need to send 0x48 (Body)
4839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
4843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if ((finalBitSet) || (mPrivateOutput.isClosed())) {
485fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    if(mSendBodyHeader == true) {
486fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        out.write(0x49);
487fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        bodyLength += 3;
488fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        out.write((byte)(bodyLength >> 8));
489fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        out.write((byte)bodyLength);
490fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                        out.write(body);
491fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    }
4929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
493fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    if(mSendBodyHeader == true) {
4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    out.write(0x48);
495fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    bodyLength += 3;
496fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    out.write((byte)(bodyLength >> 8));
497fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    out.write((byte)bodyLength);
498fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    out.write(body);
499fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                    }
5009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((finalBitSet) && (type == ResponseCodes.OBEX_HTTP_OK) && (orginalBodyLength <= 0)) {
506238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(mSendBodyHeader) {
507fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                out.write(0x49);
508fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                orginalBodyLength = 3;
509fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                out.write((byte)(orginalBodyLength >> 8));
510fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie                out.write((byte)orginalBodyLength);
511fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie            }
5129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
514238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(skipSend == false) {
515238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mResponseSize = 3;
516238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mParent.sendResponse(type, out.toByteArray());
517238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
5189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (type == ResponseCodes.OBEX_HTTP_CONTINUE) {
5209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
521238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(mGetOperation && skipReceive) {
522238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // Here we need to check for and handle abort (throw an exception).
523238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // Any other signal received should be discarded silently (only on server side)
524238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                checkSrmRemoteAbort();
5259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
526238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // Receive and handle data (only send reply if !skipSend)
527238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // Read a complete OBEX Packet
528238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                ObexPacket packet = ObexPacket.read(mInput);
529238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
530238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                int headerId = packet.mHeaderId;
531238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                if ((headerId != ObexHelper.OBEX_OPCODE_PUT)
532238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        && (headerId != ObexHelper.OBEX_OPCODE_PUT_FINAL)
533238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        && (headerId != ObexHelper.OBEX_OPCODE_GET)
534238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        && (headerId != ObexHelper.OBEX_OPCODE_GET_FINAL)) {
535238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
536238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    /*
537238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                     * Determine if an ABORT was sent as the reply
538238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                     */
539238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if (headerId == ObexHelper.OBEX_OPCODE_ABORT) {
540238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        handleRemoteAbort();
5419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } else {
542238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        // TODO:shall we send this if it occurs during SRM? Errata on the subject
543238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        mParent.sendResponse(ResponseCodes.OBEX_HTTP_BAD_REQUEST, null);
544238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        mClosed = true;
545238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        mExceptionString = "Bad Request Received";
546238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        throw new IOException("Bad Request Received");
5479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
548238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                } else {
5499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
550238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if ((headerId == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
551238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        finalBitSet = true;
552238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    } else if (headerId == ObexHelper.OBEX_OPCODE_GET_FINAL) {
553238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        mRequestFinished = true;
5549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
5559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
556238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    /*
557238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                     * Determine if the packet length is larger than the negotiated packet size
558238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                     */
559238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if (packet.mLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
560238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        mParent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null);
561238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        throw new IOException("Packet received was too large");
5629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
5639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
564238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    /*
565238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                     * Determine if any headers were sent in the initial request
566238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                     */
567238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if (packet.mLength > 3 || (mSrmEnabled && packet.mLength == 3)) {
568238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        if(handleObexPacket(packet) == false) {
569238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                            return false;
570238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        }
5719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
5729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
573238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
5749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return true;
5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
5779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
5789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
5809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
582238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * This method will look for an abort from the peer during a SRM transfer.
583238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * The function will not block if no data has been received from the remote device.
584238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * If data have been received, the function will block while reading the incoming
585238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * OBEX package.
586238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * An Abort request will be handled, and cause an IOException("Abort Received").
587238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * Other messages will be discarded silently as per GOEP specification.
588238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * @throws IOException if an abort request have been received.
589238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     * TODO: I think this is an error in the specification. If we discard other messages,
590238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *       the peer device will most likely stall, as it will not receive the expected
591238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *       response for the message...
592238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *       I'm not sure how to understand "Receipt of invalid or unexpected SRM or SRMP
593238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *       header values shall be ignored by the receiving device."
594238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *       If any signal is received during an active SRM transfer it is unexpected regardless
595238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     *       whether or not it contains SRM/SRMP headers...
596238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde     */
597238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private void checkSrmRemoteAbort() throws IOException {
598238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(mInput.available() > 0) {
599238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            ObexPacket packet = ObexPacket.read(mInput);
600238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            /*
601238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde             * Determine if an ABORT was sent as the reply
602238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde             */
603238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if (packet.mHeaderId == ObexHelper.OBEX_OPCODE_ABORT) {
604238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                handleRemoteAbort();
605238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            } else {
606238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                // TODO: should we throw an exception here anyway? - don't see how to
607238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                //       ignore SRM/SRMP headers without ignoring the complete signal
608238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                //       (in this particular case).
609238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                Log.w(TAG, "Received unexpected request from client - discarding...\n"
610238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                        + "   headerId: " + packet.mHeaderId + " length: " + packet.mLength);
611238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            }
612238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
613238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    }
614238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
615238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private void handleRemoteAbort() throws IOException {
616238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        /* TODO: To increase the speed of the abort operation in SRM, we need
617238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde         *       to be able to flush the L2CAP queue for the PSM in use.
618238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde         *       This could be implemented by introducing a control
619238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde         *       message to be send over the socket, that in the abort case
620238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde         *       could carry a flush command. */
621238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        mParent.sendResponse(ResponseCodes.OBEX_HTTP_OK, null);
622238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        mClosed = true;
623238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        isAborted = true;
624238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        mExceptionString = "Abort Received";
625238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        throw new IOException("Abort Received");
626238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    }
627238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
628238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    /**
62905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Sends an ABORT message to the server. By calling this method, the
6309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * corresponding input and output streams will be closed along with this
6319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * object.
63205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if the transaction has already ended or if an OBEX
63305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         server called this method
6349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void abort() throws IOException {
6369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        throw new IOException("Called from a server");
6379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns the headers that have been received during the operation.
64105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Modifying the object returned has no effect on the headers that are sent
64205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * or retrieved.
6439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the headers received during this <code>Operation</code>
6442e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if this <code>Operation</code> has been closed
6459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6463998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public HeaderSet getReceivedHeader() throws IOException {
6479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
6483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return requestHeader;
6499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Specifies the headers that should be sent in the next OBEX message that
6539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * is sent.
6549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param headers the headers to send in the next message
65505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if this <code>Operation</code> has been closed or the
65605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         transaction has ended and no further messages will be exchanged
6572e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IllegalArgumentException if <code>headers</code> was not created
65805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         by a call to <code>ServerRequestHandler.createHeaderSet()</code>
6599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void sendHeaders(HeaderSet headers) throws IOException {
6619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
6629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (headers == null) {
6643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            throw new IOException("Headers may not be null");
6659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int[] headerList = headers.getHeaderList();
6689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (headerList != null) {
6699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            for (int i = 0; i < headerList.length; i++) {
6703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                replyHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
6719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
67705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Retrieves the response code retrieved from the server. Response codes are
67805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * defined in the <code>ResponseCodes</code> interface.
6799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the response code retrieved from the server
6802e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an error occurred in the transport layer during
68105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         the transaction; if this method is called on a
68205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         <code>HeaderSet</code> object created by calling
68305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         <code>createHeaderSet</code> in a <code>ClientSession</code>
68405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         object; if this is called from a server
6859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public int getResponseCode() throws IOException {
6879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        throw new IOException("Called from a server");
6889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Always returns <code>null</code>
6929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return <code>null</code>
6939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public String getEncoding() {
6959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return null;
6969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns the type of content that the resource connected to is providing.
7009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * E.g. if the connection is via HTTP, then the value of the content-type
7019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * header field is returned.
7029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the content type of the resource that the URL references, or
70305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         <code>null</code> if not known
7049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public String getType() {
7069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
7073998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            return (String)requestHeader.getHeader(HeaderSet.TYPE);
7089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (IOException e) {
7099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
7109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Returns the length of the content which is being provided. E.g. if the
71505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * connection is via HTTP, then the value of the content-length header field
71605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * is returned.
7179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the content length of the resource that this connection's URL
71805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         references, or -1 if the content length is not known
7199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public long getLength() {
7219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
7223998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            Long temp = (Long)requestHeader.getHeader(HeaderSet.LENGTH);
7239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (temp == null) {
7259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return -1;
7269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
7279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return temp.longValue();
7289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
7299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (IOException e) {
7309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return -1;
7319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public int getMaxPacketSize() {
73565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        return mMaxPacketLength - 6 - getHeaderLength();
73665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue    }
73765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue
73865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue    public int getHeaderLength() {
73965208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        long id = mListener.getConnectionId();
74065208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        if (id == -1) {
74165208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            replyHeader.mConnectionID = null;
74265208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        } else {
74365208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
74465208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        }
74565208317ba9d16486b47ebcaa868c596d424c87fLixin Yue
74665208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        byte[] headerArray = ObexHelper.createHeader(replyHeader, false);
74765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue
74865208317ba9d16486b47ebcaa868c596d424c87fLixin Yue        return headerArray.length;
7499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Open and return an input stream for a connection.
7539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return an input stream
7542e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
7559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public InputStream openInputStream() throws IOException {
7579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
7583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return mPrivateInput;
7599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Open and return a data input stream for a connection.
7639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return an input stream
7642e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
7659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public DataInputStream openDataInputStream() throws IOException {
7679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return new DataInputStream(openInputStream());
7689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Open and return an output stream for a connection.
7729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return an output stream
7732e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
7749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public OutputStream openOutputStream() throws IOException {
7769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
7779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mPrivateOutputOpen) {
7799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("no more input streams available, stream already opened");
7803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        }
7819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (!mRequestFinished) {
7839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("no  output streams available ,request not finished");
7843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        }
7859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7863998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mPrivateOutput == null) {
78765208317ba9d16486b47ebcaa868c596d424c87fLixin Yue            mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
7889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7893998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mPrivateOutputOpen = true;
7903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        return mPrivateOutput;
7919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Open and return a data output stream for a connection.
7959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return an output stream
7962e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an I/O error occurs
7979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public DataOutputStream openDataOutputStream() throws IOException {
7999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return new DataOutputStream(openOutputStream());
8009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Closes the connection and ends the transaction
8042e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if the operation has already ended or is closed
8059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void close() throws IOException {
8079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ensureOpen();
8083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mClosed = true;
8099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Verifies that the connection is open and no exceptions should be thrown.
8132e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an exception needs to be thrown
8149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void ensureOpen() throws IOException {
8163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mExceptionString != null) {
8173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            throw new IOException(mExceptionString);
8189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mClosed) {
8209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throw new IOException("Operation has already ended");
8219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
82505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Verifies that additional information may be sent. In other words, the
8269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * operation is not done.
8279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <P>
82805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Included to implement the BaseStream interface only. It does not do
8299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * anything on the server side since the operation of the Operation object
8309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * is not done until after the handler returns from its method.
8312e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if the operation is completed
8329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void ensureNotDone() throws IOException {
8349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
83705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * Called when the output or input stream is closed. It does not do anything
83805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * on the server side since the operation of the Operation object is not
83905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * done until after the handler returns from its method.
8409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param inStream <code>true</code> if the input stream is closed;
84105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *        <code>false</code> if the output stream is closed
8422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException if an IO error occurs
8439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void streamClosed(boolean inStream) throws IOException {
8459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
847fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie
848fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    public void noBodyHeader(){
849fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie        mSendBodyHeader = false;
850fe3807a5b23f54f6539436d71aa0cd931a2b76f0Matthew Xie    }
8519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
852