109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/*
209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * All rights reserved.
509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Redistribution and use in source and binary forms, with or without
709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * modification, are permitted provided that the following conditions are met:
809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Redistributions of source code must retain the above copyright notice,
1009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * this list of conditions and the following disclaimer.
1109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
1209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
1309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * this list of conditions and the following disclaimer in the documentation
1409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * and/or other materials provided with the distribution.
1509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
1609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
1709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * may be used to endorse or promote products derived from this software
1809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * without specific prior written permission.
1909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
2009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
3109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */
3209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypackage com.android.bluetooth.opp;
3409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.BufferedOutputStream;
3609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.File;
3709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.IOException;
3809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.InputStream;
399d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejunimport java.util.Arrays;
4009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
4109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.ContentValues;
4209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Context;
4309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Intent;
4409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.net.Uri;
4509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Handler;
4609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Message;
4752236de777c23788df8147de15912a57e8bc36ddTao Liejunimport android.os.PowerManager;
4852236de777c23788df8147de15912a57e8bc36ddTao Liejunimport android.os.PowerManager.WakeLock;
4909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.util.Log;
5009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.webkit.MimeTypeMap;
5109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
5209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.HeaderSet;
5309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ObexTransport;
5409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.Operation;
5509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ResponseCodes;
5609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ServerRequestHandler;
5709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ServerSession;
5809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
59bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bondeimport com.android.bluetooth.BluetoothObexTransport;
60bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde
6109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/**
6209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * This class runs as an OBEX server
6309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */
6409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypublic class BluetoothOppObexServerSession extends ServerRequestHandler implements
6509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BluetoothOppObexSession {
6609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
67ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final String TAG = "BtOppObexServer";
68ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final boolean D = Constants.DEBUG;
69ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final boolean V = Constants.VERBOSE;
7009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private ObexTransport mTransport;
7209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private Context mContext;
7409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private Handler mCallback = null;
7609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* status when server is blocking for user/auto confirmation */
7809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean mServerBlocking = true;
7909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* the current transfer info */
8109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppShareInfo mInfo;
8209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* info id when we insert the record */
8409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int mLocalShareInfoId;
8509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int mAccepted = BluetoothShare.USER_CONFIRMATION_PENDING;
8709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean mInterrupted = false;
8909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private ServerSession mSession;
9109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private long mTimestamp;
9309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppReceiveFileInfo mFileInfo;
9509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9652236de777c23788df8147de15912a57e8bc36ddTao Liejun    private WakeLock mPartialWakeLock;
9752236de777c23788df8147de15912a57e8bc36ddTao Liejun
981ac5507790a87810061a19dadec36eb328a222eaTao Liejun    boolean mTimeoutMsgSent = false;
991ac5507790a87810061a19dadec36eb328a222eaTao Liejun
10009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public BluetoothOppObexServerSession(Context context, ObexTransport transport) {
10109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mContext = context;
10209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mTransport = transport;
10352236de777c23788df8147de15912a57e8bc36ddTao Liejun        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
10452236de777c23788df8147de15912a57e8bc36ddTao Liejun        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
10509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
10609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void unblock() {
10809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mServerBlocking = false;
10909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
11009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
11209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Called when connection is accepted from remote, to retrieve the first
11309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Header then wait for user confirmation
11409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
115db94389c30d5ad5555a922d28868b119e1c6f2e1Andre Eisenbach    public void preStart() {
11609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        try {
117ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly            if (D) Log.d(TAG, "Create ServerSession with transport " + mTransport.toString());
11809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mSession = new ServerSession(mTransport, this, null);
11909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } catch (IOException e) {
12009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "Create server session error" + e);
12109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
12209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
12309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
12509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Called from BluetoothOppTransfer to start the "Transfer"
12609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
1278eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen    public void start(Handler handler, int numShares) {
128ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "Start!");
12909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mCallback = handler;
13009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
13109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
13209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
13309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
1346769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun     * Called from BluetoothOppTransfer to cancel the "Transfer" Otherwise,
1356769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun     * server should end by itself.
13609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
13709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void stop() {
13809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
13909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * TODO now we implement in a tough way, just close the socket.
14009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * maybe need nice way
14109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
142ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "Stop!");
14309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mInterrupted = true;
14409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mSession != null) {
14509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
14609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mSession.close();
14709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mTransport.close();
14809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (IOException e) {
14909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.e(TAG, "close mTransport error" + e);
15009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
15109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
1521ac5507790a87810061a19dadec36eb328a222eaTao Liejun        mCallback = null;
1531ac5507790a87810061a19dadec36eb328a222eaTao Liejun        mSession = null;
15409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
15509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
15609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void addShare(BluetoothOppShareInfo info) {
157ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "addShare for id " + info.mId);
15809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mInfo = info;
15909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mFileInfo = processShareInfo();
16009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
16109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
16209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
16309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public int onPut(Operation op) {
164ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "onPut " + op.toString());
16509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        HeaderSet request;
16609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        String name, mimeType;
16709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Long length;
16809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
16909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int obexResponse = ResponseCodes.OBEX_HTTP_OK;
17009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
17109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /**
17209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * For multiple objects, reject further objects after user deny the
17309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * first one
17409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
17509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mAccepted == BluetoothShare.USER_CONFIRMATION_DENIED) {
17609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return ResponseCodes.OBEX_HTTP_FORBIDDEN;
17709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
17809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
17903f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen        String destination;
180bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if (mTransport instanceof BluetoothObexTransport) {
181bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            destination = ((BluetoothObexTransport)mTransport).getRemoteAddress();
18203f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen        } else {
18303f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen            destination = "FF:FF:FF:00:00:00";
18403f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen        }
18503f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen        boolean isWhitelisted = BluetoothOppManager.getInstance(mContext).
18603f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen                isWhitelisted(destination);
18703f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen
18809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        try {
18909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            boolean pre_reject = false;
19003f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen
1916769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun            request = op.getReceivedHeader();
192ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly            if (V) Constants.logHeader(request);
19309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            name = (String)request.getHeader(HeaderSet.NAME);
19409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            length = (Long)request.getHeader(HeaderSet.LENGTH);
19509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mimeType = (String)request.getHeader(HeaderSet.TYPE);
19609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
19709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (length == 0) {
198ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.w(TAG, "length is 0, reject the transfer");
19909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                pre_reject = true;
20009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_LENGTH_REQUIRED;
20109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
20209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
20309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (name == null || name.equals("")) {
204ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.w(TAG, "name is null or empty, reject the transfer");
20509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                pre_reject = true;
20609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
20709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
20809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
20909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (!pre_reject) {
21009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /* first we look for Mimetype in Android map */
21109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                String extension, type;
21259256dee3f9787fd660c346d61e0271ecd4bfe9aJaikumar Ganesh                int dotIndex = name.lastIndexOf(".");
21303f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen                if (dotIndex < 0 && mimeType == null) {
21403f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen                    if (D) Log.w(TAG, "There is no file extension or mime type," +
21503f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen                            "reject the transfer");
21609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    pre_reject = true;
21709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    obexResponse = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
21809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
2191ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    extension = name.substring(dotIndex + 1).toLowerCase();
22009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    MimeTypeMap map = MimeTypeMap.getSingleton();
22109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    type = map.getMimeTypeFromExtension(extension);
222ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) Log.v(TAG, "Mimetype guessed from extension " + extension + " is " + type);
22309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (type != null) {
22409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mimeType = type;
22509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
22609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else {
22709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (mimeType == null) {
228ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                            if (D) Log.w(TAG, "Can't get mimetype, reject the transfer");
22909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            pre_reject = true;
230239bc526513429995c61c4148c105725c395b1a9Jackson Fan                            obexResponse = ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE;
23109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
23209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
23309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (mimeType != null) {
23409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mimeType = mimeType.toLowerCase();
23509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
23609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
23709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
23809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
239fb946935fe50d957e835ac00a592bd3d222edef3Oscar Montemayor            // Reject policy: anything outside the "white list" plus unspecified
24076d17f9aff4a4aaad0f5af91eee1028473c10b16Olsson            // MIME Types. Also reject everything in the "black list".
24109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (!pre_reject
24276d17f9aff4a4aaad0f5af91eee1028473c10b16Olsson                    && (mimeType == null
24303f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen                            || (!isWhitelisted && !Constants.mimeTypeMatches(mimeType,
24403f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen                                    Constants.ACCEPTABLE_SHARE_INBOUND_TYPES))
24576d17f9aff4a4aaad0f5af91eee1028473c10b16Olsson                            || Constants.mimeTypeMatches(mimeType,
24676d17f9aff4a4aaad0f5af91eee1028473c10b16Olsson                                    Constants.UNACCEPTABLE_SHARE_INBOUND_TYPES))) {
247ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.w(TAG, "mimeType is null or in unacceptable list, reject the transfer");
24809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                pre_reject = true;
24909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE;
25009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
25109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (pre_reject && obexResponse != ResponseCodes.OBEX_HTTP_OK) {
2531ac5507790a87810061a19dadec36eb328a222eaTao Liejun                // some bad implemented client won't send disconnect
25409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                return obexResponse;
25509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
25609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } catch (IOException e) {
25809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "get getReceivedHeaders error " + e);
25909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
26009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
26109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
26209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        ContentValues values = new ContentValues();
26309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
26409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.FILENAME_HINT, name);
2653aecf54308d60eea10fe10a5c18e4dff455aef66Pradeep Panigrahi
2663aecf54308d60eea10fe10a5c18e4dff455aef66Pradeep Panigrahi        values.put(BluetoothShare.TOTAL_BYTES, length);
2673aecf54308d60eea10fe10a5c18e4dff455aef66Pradeep Panigrahi
26809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.MIMETYPE, mimeType);
26909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
2708099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen        values.put(BluetoothShare.DESTINATION, destination);
27109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
27209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_INBOUND);
27309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.TIMESTAMP, mTimestamp);
27409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
27509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /** It's not first put if !serverBlocking, so we auto accept it */
27601b3991ff968cbc8300fdaf42bbe3f5614ac4c56Andre Eisenbach        if (!mServerBlocking && (mAccepted == BluetoothShare.USER_CONFIRMATION_CONFIRMED ||
27701b3991ff968cbc8300fdaf42bbe3f5614ac4c56Andre Eisenbach                mAccepted == BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED)) {
27809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            values.put(BluetoothShare.USER_CONFIRMATION,
27909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED);
28009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
28109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
28203f25a2055e51bcc5e8870642763b502956b6830Martijn Coenen        if (isWhitelisted) {
2838099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            values.put(BluetoothShare.USER_CONFIRMATION,
2848099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                    BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED);
2858eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen
2868099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen        }
2878099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen
28809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Uri contentUri = mContext.getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
28909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mLocalShareInfoId = Integer.parseInt(contentUri.getPathSegments().get(1));
29009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
291ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Log.v(TAG, "insert contentUri: " + contentUri);
2929d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        if (V) Log.v(TAG, "mLocalShareInfoId = " + mLocalShareInfoId);
29309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
29409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        synchronized (this) {
295f6ae67403c20cec20bc8f906411fce4c9ea769f0Sunny Goyal            mPartialWakeLock.acquire();
2964492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh            mServerBlocking = true;
29709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
298df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun
29909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                while (mServerBlocking) {
30009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    wait(1000);
3011ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    if (mCallback != null && !mTimeoutMsgSent) {
30209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mCallback.sendMessageDelayed(mCallback
30309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                .obtainMessage(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT),
30409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                BluetoothOppObexSession.SESSION_TIMEOUT);
3051ac5507790a87810061a19dadec36eb328a222eaTao Liejun                        mTimeoutMsgSent = true;
306ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                        if (V) Log.v(TAG, "MSG_CONNECT_TIMEOUT sent");
30709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
30809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
30909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (InterruptedException e) {
310ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (V) Log.v(TAG, "Interrupted in onPut blocking");
31109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
31209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
313ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "Server unblocked ");
3149d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        synchronized (this) {
3159d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            if (mCallback != null && mTimeoutMsgSent) {
3169d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun                mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT);
3179d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            }
3186769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        }
31909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
32009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /* we should have mInfo now */
32109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
32209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
32309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * TODO check if this mInfo match the one that we insert before server
32409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * blocking? just to make sure no error happens
32509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
32609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mInfo.mId != mLocalShareInfoId) {
32709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "Unexpected error!");
32809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
32909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mAccepted = mInfo.mConfirm;
33009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
331ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Log.v(TAG, "after confirm: userAccepted=" + mAccepted);
33209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int status = BluetoothShare.STATUS_SUCCESS;
33309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
33409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mAccepted == BluetoothShare.USER_CONFIRMATION_CONFIRMED
3358099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                || mAccepted == BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED
3368099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                || mAccepted == BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED) {
33709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /* Confirm or auto-confirm */
33809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
33909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mFileInfo.mFileName == null) {
34009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = mFileInfo.mStatus;
34109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /* TODO need to check if this line is correct */
34209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mInfo.mStatus = mFileInfo.mStatus;
34309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Constants.updateShareStatus(mContext, mInfo.mId, status);
34409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
34509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
34609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
34709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
34809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mFileInfo.mFileName != null) {
34909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
35009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                ContentValues updateValues = new ContentValues();
35109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId);
35209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                updateValues.put(BluetoothShare._DATA, mFileInfo.mFileName);
35309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING);
35409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mContext.getContentResolver().update(contentUri, updateValues, null, null);
35509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
35609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = receiveFile(mFileInfo, op);
35709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /*
35809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * TODO map status to obex response code
35909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 */
36009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (status != BluetoothShare.STATUS_SUCCESS) {
36109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    obexResponse = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
36209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
36309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Constants.updateShareStatus(mContext, mInfo.mId, status);
36409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
36509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
36609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (status == BluetoothShare.STATUS_SUCCESS) {
36709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Message msg = Message.obtain(mCallback, BluetoothOppObexSession.MSG_SHARE_COMPLETE);
36809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                msg.obj = mInfo;
36909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                msg.sendToTarget();
37009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
3711ac5507790a87810061a19dadec36eb328a222eaTao Liejun                if (mCallback != null) {
3721ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    Message msg = Message.obtain(mCallback,
3731ac5507790a87810061a19dadec36eb328a222eaTao Liejun                            BluetoothOppObexSession.MSG_SESSION_ERROR);
3741ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    mInfo.mStatus = status;
3751ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    msg.obj = mInfo;
3761ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    msg.sendToTarget();
3771ac5507790a87810061a19dadec36eb328a222eaTao Liejun                }
37809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
37909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else if (mAccepted == BluetoothShare.USER_CONFIRMATION_DENIED
38009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                || mAccepted == BluetoothShare.USER_CONFIRMATION_TIMEOUT) {
38109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /* user actively deny the inbound transfer */
38209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /*
38309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Note There is a question: what's next if user deny the first obj?
38409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Option 1 :continue prompt for next objects
38509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Option 2 :reject next objects and finish the session
38609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Now we take option 2:
38709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             */
38852236de777c23788df8147de15912a57e8bc36ddTao Liejun
38952236de777c23788df8147de15912a57e8bc36ddTao Liejun            Log.i(TAG, "Rejected incoming request");
3901ac5507790a87810061a19dadec36eb328a222eaTao Liejun            if (mFileInfo.mFileName != null) {
3911ac5507790a87810061a19dadec36eb328a222eaTao Liejun                try {
3921ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    mFileInfo.mOutputStream.close();
3931ac5507790a87810061a19dadec36eb328a222eaTao Liejun                } catch (IOException e) {
3941ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    Log.e(TAG, "error close file stream");
3951ac5507790a87810061a19dadec36eb328a222eaTao Liejun                }
3961ac5507790a87810061a19dadec36eb328a222eaTao Liejun                new File(mFileInfo.mFileName).delete();
3971ac5507790a87810061a19dadec36eb328a222eaTao Liejun            }
3981ac5507790a87810061a19dadec36eb328a222eaTao Liejun            // set status as local cancel
3991ac5507790a87810061a19dadec36eb328a222eaTao Liejun            status = BluetoothShare.STATUS_CANCELED;
40009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Constants.updateShareStatus(mContext, mInfo.mId, status);
40109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            obexResponse = ResponseCodes.OBEX_HTTP_FORBIDDEN;
4021ac5507790a87810061a19dadec36eb328a222eaTao Liejun
40309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Message msg = Message.obtain(mCallback);
40409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.what = BluetoothOppObexSession.MSG_SHARE_INTERRUPTED;
4051ac5507790a87810061a19dadec36eb328a222eaTao Liejun            mInfo.mStatus = status;
40609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.obj = mInfo;
40709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.sendToTarget();
40809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
40909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return obexResponse;
41009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
41109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
41209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int receiveFile(BluetoothOppReceiveFileInfo fileInfo, Operation op) {
41309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
41409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * implement receive file
41509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
41609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int status = -1;
41709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BufferedOutputStream bos = null;
41809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
41909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        InputStream is = null;
42009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        boolean error = false;
42109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        try {
42209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            is = op.openInputStream();
42309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } catch (IOException e1) {
42409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "Error when openInputStream");
42509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            status = BluetoothShare.STATUS_OBEX_DATA_ERROR;
42609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            error = true;
42709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
42809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
42909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId);
43009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
43109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!error) {
43209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            ContentValues updateValues = new ContentValues();
43309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            updateValues.put(BluetoothShare._DATA, fileInfo.mFileName);
43409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mContext.getContentResolver().update(contentUri, updateValues, null, null);
43509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
43609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
437cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri        long position = 0;
438cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri        long percent = 0;
439cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri        long prevPercent = 0;
440cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri
44109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!error) {
4421ac5507790a87810061a19dadec36eb328a222eaTao Liejun            bos = new BufferedOutputStream(fileInfo.mOutputStream, 0x10000);
44309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
44409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
44509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!error) {
44609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int outputBufferSize = op.getMaxPacketSize();
44709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            byte[] b = new byte[outputBufferSize];
44809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int readLength = 0;
44952236de777c23788df8147de15912a57e8bc36ddTao Liejun            long timestamp = 0;
45009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
45109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                while ((!mInterrupted) && (position != fileInfo.mLength)) {
45209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
453ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) timestamp = System.currentTimeMillis();
45409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
45509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    readLength = is.read(b);
45609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
45709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (readLength == -1) {
458ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                        if (D) Log.d(TAG, "Receive file reached stream end at position" + position);
45909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        break;
46009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
46109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
46209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    bos.write(b, 0, readLength);
46309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    position += readLength;
464cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                    percent = position * 100 / fileInfo.mLength;
46509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
466ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) {
46709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Receive file position = " + position + " readLength "
46809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + readLength + " bytes took "
46909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + (System.currentTimeMillis() - timestamp) + " ms");
47009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
47109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
472cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                    // Update the Progress Bar only if there is change in percentage
473cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                    if (percent > prevPercent) {
474cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                        ContentValues updateValues = new ContentValues();
475cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                        updateValues.put(BluetoothShare.CURRENT_BYTES, position);
476cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                        mContext.getContentResolver().update(contentUri, updateValues, null, null);
477cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                        prevPercent = percent;
478cc810f757b28d95d3a67d1810426bbedd69a0d88Deepak A Metri                    }
47909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
48009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (IOException e1) {
48109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.e(TAG, "Error when receiving file");
4829abe9c9e1ccad600b1069490293d78dfd984017bAndreas Areskoug                /* OBEX Abort packet received from remote device */
4839abe9c9e1ccad600b1069490293d78dfd984017bAndreas Areskoug                if ("Abort Received".equals(e1.getMessage())) {
4849abe9c9e1ccad600b1069490293d78dfd984017bAndreas Areskoug                    status = BluetoothShare.STATUS_CANCELED;
4859abe9c9e1ccad600b1069490293d78dfd984017bAndreas Areskoug                } else {
4869abe9c9e1ccad600b1069490293d78dfd984017bAndreas Areskoug                    status = BluetoothShare.STATUS_OBEX_DATA_ERROR;
4879abe9c9e1ccad600b1069490293d78dfd984017bAndreas Areskoug                }
48809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                error = true;
48909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
49009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
49109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
49209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mInterrupted) {
493ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly            if (D) Log.d(TAG, "receiving file interrupted by user.");
49409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            status = BluetoothShare.STATUS_CANCELED;
49509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else {
49609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (position == fileInfo.mLength) {
497ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.d(TAG, "Receiving file completed for " + fileInfo.mFileName);
49809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = BluetoothShare.STATUS_SUCCESS;
49909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
500ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.d(TAG, "Reading file failed at " + position + " of " + fileInfo.mLength);
50109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (status == -1) {
50209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    status = BluetoothShare.STATUS_UNKNOWN_ERROR;
50309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
50409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
50509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
50609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
50709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (bos != null) {
50809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
50909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                bos.close();
51009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (IOException e) {
51109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.e(TAG, "Error when closing stream after send");
51209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
51309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
51409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return status;
51509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
51609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
51709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppReceiveFileInfo processShareInfo() {
518ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "processShareInfo() " + mInfo.mId);
51909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BluetoothOppReceiveFileInfo fileInfo = BluetoothOppReceiveFileInfo.generateFileInfo(
52009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mContext, mInfo.mId);
521ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) {
52209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Generate BluetoothOppReceiveFileInfo:");
52309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "filename  :" + fileInfo.mFileName);
52409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "length    :" + fileInfo.mLength);
52509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "status    :" + fileInfo.mStatus);
52609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
52709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return fileInfo;
52809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
52909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
53009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
53109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public int onConnect(HeaderSet request, HeaderSet reply) {
53209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
533ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "onConnect");
534ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Constants.logHeader(request);
5358eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        Long objectCount = null;
5369d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        try {
5379d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            byte[] uuid = (byte[])request.getHeader(HeaderSet.TARGET);
5389d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            if (V) Log.v(TAG, "onConnect(): uuid =" + Arrays.toString(uuid));
5399d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            if(uuid != null) {
540eb1192b4208d4bf77c92011822e6d171b9f09980Jaikumar Ganesh                 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
5419d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            }
5428eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen
5438eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            objectCount = (Long) request.getHeader(HeaderSet.COUNT);
5449d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        } catch (IOException e) {
5459d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            Log.e(TAG, e.toString());
5469d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
5479d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        }
5488eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        String destination;
549bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde        if (mTransport instanceof BluetoothObexTransport) {
550bbb4110b455b3aa29106d5b4f0a37e1be8e09475Casper Bonde            destination = ((BluetoothObexTransport)mTransport).getRemoteAddress();
5518eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        } else {
5528eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            destination = "FF:FF:FF:00:00:00";
5538eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        }
5548eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        boolean isHandover = BluetoothOppManager.getInstance(mContext).
5558eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen                isWhitelisted(destination);
5568eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        if (isHandover) {
5578eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            // Notify the handover requester file transfer has started
5588eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            Intent intent = new Intent(Constants.ACTION_HANDOVER_STARTED);
5598eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            if (objectCount != null) {
5608eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen                intent.putExtra(Constants.EXTRA_BT_OPP_OBJECT_COUNT, objectCount.intValue());
5618eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            } else {
5628eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen                intent.putExtra(Constants.EXTRA_BT_OPP_OBJECT_COUNT,
5638eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen                        Constants.COUNT_HEADER_UNAVAILABLE);
5648eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            }
5658eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            intent.putExtra(Constants.EXTRA_BT_OPP_ADDRESS, destination);
5668eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen            mContext.sendBroadcast(intent, Constants.HANDOVER_STATUS_PERMISSION);
5678eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen        }
56809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mTimestamp = System.currentTimeMillis();
56909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return ResponseCodes.OBEX_HTTP_OK;
57009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
57109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
57209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
57309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void onDisconnect(HeaderSet req, HeaderSet resp) {
574ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "onDisconnect");
57509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        resp.responseCode = ResponseCodes.OBEX_HTTP_OK;
57609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
57709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
5784492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh    private synchronized void releaseWakeLocks() {
57932e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        if (mPartialWakeLock.isHeld()) {
58032e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun            mPartialWakeLock.release();
58132e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        }
5824492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh    }
5834492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh
5844492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh    @Override
5854492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh    public void onClose() {
5864492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh        if (V) Log.v(TAG, "release WakeLock");
5874492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh        releaseWakeLocks();
5884492b2c66cf3b26fd988f3b7f1f5df6cc9ed49f2Jaikumar Ganesh
5899d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        /* onClose could happen even before start() where mCallback is set */
5909d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        if (mCallback != null) {
5919d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            Message msg = Message.obtain(mCallback);
5929d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            msg.what = BluetoothOppObexSession.MSG_SESSION_COMPLETE;
5939d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            msg.obj = mInfo;
5949d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun            msg.sendToTarget();
5959d9e511fe7425fb3105ece227ecedb43d6333333Tao Liejun        }
59609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
59709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly}
598