ServerSession.java revision 2e0da96e757a977154063f980d3f4e1abd41cf09
19439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/*
29439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
39439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * All rights reserved.
59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Redistribution and use in source and binary forms, with or without
79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * modification, are permitted provided that the following conditions are met:
89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions of source code must retain the above copyright notice,
109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer.
119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer in the documentation
149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * and/or other materials provided with the distribution.
159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * may be used to endorse or promote products derived from this software
189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * without specific prior written permission.
199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage javax.obex;
349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
352e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.InputStream;
362e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.IOException;
372e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.OutputStream;
389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * This class in an implementation of the ServerSession interface.
419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide
439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypublic class ServerSession implements Runnable, ObexSession {
459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private ObexTransport client;
479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private InputStream input;
499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private OutputStream output;
519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private ServerRequestHandler listener;
539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private Thread processThread;
559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private int maxPacketLength;
579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private Authenticator authenticator;
599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    byte[] challengeDigest;
619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
622e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly    private boolean isClosed;
639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates new ServerSession.
669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param conn
689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the connection to the client
699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param handler
719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the event listener that will process requests
729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param auth
749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the authenticator to use with this connection
759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
762e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an error occurred while opening the input and output
789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                streams
799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public ServerSession(ObexTransport conn, ServerRequestHandler handler, Authenticator auth)
819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throws IOException {
829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        authenticator = auth;
839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        client = conn;
849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        input = client.openInputStream();
859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output = client.openOutputStream();
869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        listener = handler;
879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        maxPacketLength = 256;
889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        isClosed = false;
909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        processThread = new Thread(this);
919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        processThread.start();
929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /* removed as they're provided to the API user. Not used internally. */
959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /*
969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     public boolean isCreatedServer() {
979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (client instanceof BTConnection)
989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return ((BTConnection)client).isServerCreated();
999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        else
1009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
1019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public boolean isClosed() {
1049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (client instanceof BTConnection)
1059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return ((BTConnection)client).isClosed();
1069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        else
1079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
1089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public int getConnectionHandle() {
1119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (client instanceof BTConnection)
1129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return ((BTConnection)client).getConnectionHandle();
1139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        else
1149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return -1;
1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public RemoteDevice getRemoteDevice() {
1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (client instanceof BTConnection)
1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return ((BTConnection)client).getRemoteDevice();
1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        else
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return null;
1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }*/
1239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Processes requests made to the server and forwards them to the
1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * appropriate event listener.
1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void run() {
1299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
1309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            boolean done = false;
1329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            while (!done && !isClosed) {
1339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                int requestType = input.read();
1349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                switch (requestType) {
1359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x80:
1369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleConnectRequest();
1379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x81:
1409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleDisconnectRequest();
1419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        done = true;
1429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x03:
1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x83:
1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleGetRequest(requestType);
1479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x02:
1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x82:
1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handlePutRequest(requestType);
1529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case 0x85:
1559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleSetPathRequest();
1569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case -1:
1599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        done = true;
1609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    default:
1639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        /*
1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * Received a request type that is not recognized so I am
1669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * just going to read the packet and send a not implemented
1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * to the client
1689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         */
1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        int length = input.read();
1709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        length = (length << 8) + input.read();
1719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        for (int i = 3; i < length; i++) {
1729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            input.read();
1739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
1749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
1759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        // done = true;
1779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
1799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (NullPointerException e) {
1819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
1829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        close();
1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a PUT request from a client. This method will provide a
1889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object to the request handler. The
1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will handle the rest of the request.
1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * It will also send replies and receive requests until the final reply
1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * should be sent. When the final reply should be sent, this method will get
1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * the response code to use and send the reply. The
1939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will always reply with a
1949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
1959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * needed.
1969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
1979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param type
1989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the type of request received; either 0x02 or 0x82
1999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2002e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
2019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an error occurred at the transport layer
2029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handlePutRequest(int type) throws IOException {
2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ServerOperation client = new ServerOperation(this, input, type, maxPacketLength, listener);
2059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int response = -1;
2079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if ((client.finalBitSet) && !client.isValidBody()) {
2099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                response = validateResponseCode(listener.onDelete(client.requestHeaders,
2109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        client.replyHeaders));
2119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
2129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                response = validateResponseCode(listener.onPut(client));
2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (response != ResponseCodes.OBEX_HTTP_OK) {
2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                client.sendReply(response);
2169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else if (!client.isAborted) {
2179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // wait for the final bit
2189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (!client.finalBitSet) {
2192e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    client.sendReply(ObexHelper.OBEX_HTTP_CONTINUE);
2209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
2219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                client.sendReply(response);
2229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
2249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
2259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a GET request from a client. This method will provide a
2309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object to the request handler. The
2319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will handle the rest of the request.
2329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * It will also send replies and receive requests until the final reply
2339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * should be sent. When the final reply should be sent, this method will get
2349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * the response code to use and send the reply. The
2359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will always reply with a
2369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
2379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * needed.
2389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param type
2409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the type of request received; either 0x03 or 0x83
2419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
2439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an error occurred at the transport layer
2449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleGetRequest(int type) throws IOException {
2469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        ServerOperation client = new ServerOperation(this, input, type, maxPacketLength, listener);
2479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int response = validateResponseCode(listener.onGet(client));
2499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (!client.isAborted) {
2519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                client.sendReply(response);
2529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
2549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
2559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Send standard response.
2609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param code
2629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the response code to send
2639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param header
2659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the headers to include in the response
2669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2672e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
2689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an IO error occurs
2699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    protected void sendResponse(int code, byte[] header) throws IOException {
2719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 3;
2729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] data = null;
2739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (header != null) {
2759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength += header.length;
2769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data = new byte[totalLength];
2779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[0] = (byte)code;
2789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[1] = (byte)(totalLength >> 8);
2799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[2] = (byte)totalLength;
2809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(header, 0, data, 3, header.length);
2819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
2829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data = new byte[totalLength];
2839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[0] = (byte)code;
2849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[1] = (byte)0x00;
2859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[2] = (byte)totalLength;
2869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.write(data);
2889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.flush();
2899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a SETPATH request from a client. This method will read the rest
2939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * of the request from the client. Assuming the request is valid, it will
2949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * create a <code>HeaderSet</code> object to pass to the
2959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerRequestHandler</code> object. After the handler processes the
2969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * request, this method will create a reply message to send to the server
2979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * with the response code provided.
2989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
2992e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
3009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an error occurred at the transport layer
3019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
3029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleSetPathRequest() throws IOException {
3039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length;
3049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int flags;
3059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int constants;
3069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 3;
3079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] head = null;
3089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int code = -1;
3099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bytesReceived;
3109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet request = new HeaderSet();
3119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet reply = new HeaderSet();
3129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        length = input.read();
3149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        length = (length << 8) + input.read();
3159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        flags = input.read();
3169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        constants = input.read();
3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3182e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
3199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
3209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength = 3;
3219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
3229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (length > 5) {
3239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] headers = new byte[length - 5];
3249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                bytesReceived = input.read(headers);
3259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (bytesReceived != headers.length) {
3279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    bytesReceived += input.read(headers, bytesReceived, headers.length
3289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            - bytesReceived);
3299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3312e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                ObexHelper.updateHeaderSet(request, headers);
3329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (request.connectionID != null) {
3342e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
3359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
3369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    listener.setConnectionID(-1);
3379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // the Auth chan is initiated by the server.
3399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // client sent back the authResp .
3409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (request.authResp != null) {
3419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (!handleAuthResp(request.authResp)) {
3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
3432e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                        listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                                request.authResp));
3459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
3469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    request.authResp = null;
3479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
3519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // the Auth chan is initiated by the client
3529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // the server will send back the authResp to the client
3539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (request.authChall != null) {
3549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    handleAuthChall(request);
3559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    reply.authResp = new byte[request.authResp.length];
3569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    System.arraycopy(request.authResp, 0, reply.authResp, 0, reply.authResp.length);
3579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    request.authChall = null;
3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    request.authResp = null;
3599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                boolean backup = false;
3619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                boolean create = true;
3629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (!((flags & 1) == 0)) {
3639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    backup = true;
3649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if ((flags & 2) == 0) {
3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    create = false;
3679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = listener.onSetPath(request, reply, backup, create);
3719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (Exception e) {
3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
3739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    return;
3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                code = validateResponseCode(code);
3779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (reply.nonce != null) {
3799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    challengeDigest = new byte[16];
3809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16);
3819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
3829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    challengeDigest = null;
3839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                long id = listener.getConnectionID();
3869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (id == -1) {
3879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    reply.connectionID = null;
3889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
3892e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    reply.connectionID = ObexHelper.convertToByteArray(id);
3909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3922e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                head = ObexHelper.createHeader(reply, false);
3939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                totalLength += head.length;
3949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (totalLength > maxPacketLength) {
3969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength = 3;
3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    head = null;
3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
3999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Compute Length of OBEX SETPATH packet
4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] replyData = new byte[totalLength];
4059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[0] = (byte)code;
4069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[1] = (byte)(totalLength >> 8);
4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[2] = (byte)totalLength;
4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
4099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(head, 0, replyData, 3, head.length);
4109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
4119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
4129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Write the OBEX SETPATH packet to the server. Byte 0: response code
4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Byte 1&2: Connect Packet Length Byte 3 to n: headers
4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
4159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.write(replyData);
4169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.flush();
4179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
4189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
4209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a disconnect request from a client. This method will read the
4219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * rest of the request from the client. Assuming the request is valid, it
4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * will create a <code>HeaderSet</code> object to pass to the
4239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerRequestHandler</code> object. After the handler processes the
4249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * request, this method will create a reply message to send to the server.
4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
4262e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
4279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an error occurred at the transport layer
4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
4299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleDisconnectRequest() throws IOException {
4309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length;
4319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int code = ResponseCodes.OBEX_HTTP_OK;
4329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 3;
4339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] head = null;
4349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bytesReceived;
4359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet request = new HeaderSet();
4369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet reply = new HeaderSet();
4379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        length = input.read();
4399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        length = (length << 8) + input.read();
4409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4412e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
4429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
4439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength = 3;
4449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
4459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (length > 3) {
4469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] headers = new byte[length - 3];
4479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                bytesReceived = input.read(headers);
4489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (bytesReceived != headers.length) {
4509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    bytesReceived += input.read(headers, bytesReceived, headers.length
4519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            - bytesReceived);
4529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4542e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                ObexHelper.updateHeaderSet(request, headers);
4559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (request.connectionID != null) {
4582e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
4599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
4609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                listener.setConnectionID(1);
4619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (request.authResp != null) {
4649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (!handleAuthResp(request.authResp)) {
4659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
4662e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            request.authResp));
4689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                request.authResp = null;
4709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
4739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (request.authChall != null) {
4759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    handleAuthChall(request);
4769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    request.authChall = null;
4779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
4809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    listener.onDisconnect(request, reply);
4819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (Exception e) {
4829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
4839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    return;
4849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                /*
4879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * Since a client will never response to an authentication
4889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * challenge on a DISCONNECT, there is no reason to keep track
4899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * of the challenge.
4909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 *
4919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * if (reply.nonce != null) { challengeDigest = new byte[16];
4929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16); }
4939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 * else { challengeDigest = null; }
4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                 */
4959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                long id = listener.getConnectionID();
4979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (id == -1) {
4989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    reply.connectionID = null;
4999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
5002e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    reply.connectionID = ObexHelper.convertToByteArray(id);
5019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5032e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                head = ObexHelper.createHeader(reply, false);
5049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                totalLength += head.length;
5059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (totalLength > maxPacketLength) {
5079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength = 3;
5089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    head = null;
5099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
5109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Compute Length of OBEX CONNECT packet
5159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] replyData;
5169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
5179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            replyData = new byte[3 + head.length];
5189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
5199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            replyData = new byte[3];
5209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[0] = (byte)code;
5229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[1] = (byte)(totalLength >> 8);
5239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[2] = (byte)totalLength;
5249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
5259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(head, 0, replyData, 3, head.length);
5269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
5289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
5299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Byte 1&2: Connect Packet Length Byte 3 to n: headers
5309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
5319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.write(replyData);
5329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.flush();
5339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
5349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
5369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a connect request from a client. This method will read the rest
5379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * of the request from the client. Assuming the request is valid, it will
5389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * create a <code>HeaderSet</code> object to pass to the
5399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerRequestHandler</code> object. After the handler processes the
5409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * request, this method will create a reply message to send to the server
5419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * with the response code provided.
5429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
5432e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly     * @throws IOException
5449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *                if an error occurred at the transport layer
5459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
5469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleConnectRequest() throws IOException {
5479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int packetLength;
5489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int version;
5499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int flags;
5509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 7;
5519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] head = null;
5529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int code = -1;
5539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet request = new HeaderSet();
5549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet reply = new HeaderSet();
5559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bytesReceived;
5569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
5589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Read in the length of the OBEX packet, OBEX version, flags, and max
5599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * packet length
5609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
5619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        packetLength = input.read();
5629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        packetLength = (packetLength << 8) + input.read();
5639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        version = input.read();
5649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        flags = input.read();
5659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        maxPacketLength = input.read();
5669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        maxPacketLength = (maxPacketLength << 8) + input.read();
5679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // should we check it?
5692e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        if (maxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
5702e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly            maxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
5719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5732e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) {
5749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
5759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength = 7;
5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
5779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (packetLength > 7) {
5789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] headers = new byte[packetLength - 7];
5799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                bytesReceived = input.read(headers);
5809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (bytesReceived != headers.length) {
5829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    bytesReceived += input.read(headers, bytesReceived, headers.length
5839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            - bytesReceived);
5849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5862e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                ObexHelper.updateHeaderSet(request, headers);
5879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (request.connectionID != null) {
5902e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                listener.setConnectionID(ObexHelper.convertToLong(request.connectionID));
5919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
5929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                listener.setConnectionID(1);
5939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (request.authResp != null) {
5969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (!handleAuthResp(request.authResp)) {
5979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
5982e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
5999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            request.authResp));
6009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                request.authResp = null;
6029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
6059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (request.authChall != null) {
6069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    handleAuthChall(request);
6079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    reply.authResp = new byte[request.authResp.length];
6089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    System.arraycopy(request.authResp, 0, reply.authResp, 0, reply.authResp.length);
6099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    request.authChall = null;
6109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    request.authResp = null;
6119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
6149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = listener.onConnect(request, reply);
6159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = validateResponseCode(code);
6169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (reply.nonce != null) {
6189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        challengeDigest = new byte[16];
6199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        System.arraycopy(reply.nonce, 0, challengeDigest, 0, 16);
6209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } else {
6219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        challengeDigest = null;
6229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    long id = listener.getConnectionID();
6249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (id == -1) {
6259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        reply.connectionID = null;
6269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } else {
6272e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                        reply.connectionID = ObexHelper.convertToByteArray(id);
6289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6302e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    head = ObexHelper.createHeader(reply, false);
6319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength += head.length;
6329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (totalLength > maxPacketLength) {
6349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        totalLength = 7;
6359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        head = null;
6369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
6379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (Exception e) {
6399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    e.printStackTrace();
6409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength = 7;
6419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    head = null;
6429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
6439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Compute Length of OBEX CONNECT packet
6492e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] length = ObexHelper.convertToByteArray(totalLength);
6509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
6529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Write the OBEX CONNECT packet to the server. Byte 0: response code
6539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
6549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
6559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
6569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
6579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] sendData = new byte[totalLength];
6589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[0] = (byte)code;
6599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[1] = length[2];
6609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[2] = length[3];
6619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[3] = (byte)0x10;
6629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[4] = (byte)0x00;
6632e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        sendData[5] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
6642e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        sendData[6] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
6659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
6679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(head, 0, sendData, 7, head.length);
6689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.write(sendData);
6719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output.flush();
6729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Closes the server session - in detail close I/O streams and the
6769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * underlying transport layer. Internal flag is also set so that later
6779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * attempt to read/write will throw an exception.
6789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized void close() {
6809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (listener != null) {
6819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            listener.onClose();
6829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
6849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            input.close();
6859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            output.close();
6869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            client.close();
6879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            isClosed = true;
6889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
6899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        client = null;
6919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        input = null;
6929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        output = null;
6939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        listener = null;
6949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Verifies that the response code is valid. If it is not valid, it will
6989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code.
6999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
7009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param code
7019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the response code to check
7029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
7039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code>
7049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *         if <code>code</code> is not valid
7059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private int validateResponseCode(int code) {
7079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) {
7099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE)
7129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) {
7139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST)
7169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) {
7179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR)
7209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_HTTP_VERSION)) {
7219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_DATABASE_FULL)
7249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) {
7259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
7289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Called when the server received an authentication challenge header. This
7329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * will cause the authenticator to handle the authentication challenge.
7339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
7349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param header
7359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the header with the authentication challenge
7369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
7379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return <code>true</code> if the last request should be resent;
7389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *         <code>false</code> if the last request should not be resent
7399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    protected boolean handleAuthChall(HeaderSet header) {
7419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (authenticator == null) {
7429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
7439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
7469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * An authentication challenge is made up of one required and two
7479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * optional tag length value triplets. The tag 0x00 is required to be in
7489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * the authentication challenge and it represents the challenge digest
7499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * that was received. The tag 0x01 is the options tag. This tag tracks
7509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * if user ID is required and if full access will be granted. The tag
7519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * 0x02 is the realm, which provides a description of which user name
7529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * and password to use.
7539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
7542e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall);
7552e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall);
7562e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall);
7579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        String realm = "";
7599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (description != null) {
7609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            byte[] realmString = new byte[description.length - 1];
7619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(description, 1, realmString, 0, realmString.length);
7629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            switch (description[0] & 0xFF) {
7649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x00:
7669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ASCII encoding
7679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x01:
7699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-1 encoding
7709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    try {
7719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        realm = new String(realmString, "ISO8859_1");
7729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } catch (Exception e) {
7739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        throw new RuntimeException("Unsupported Encoding Scheme");
7749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
7759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0xFF:
7789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // UNICODE Encoding
7792e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    realm = ObexHelper.convertToUnicode(realmString, false);
7809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    break;
7819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x02:
7839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-2 encoding
7849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x03:
7869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-3 encoding
7879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x04:
7899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-4 encoding
7909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x05:
7929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-5 encoding
7939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x06:
7959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-6 encoding
7969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
7979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x07:
7989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-7 encoding
7999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
8009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x08:
8019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-8 encoding
8029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
8039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                case 0x09:
8049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // ISO-8859-9 encoding
8059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    // Fall through
8069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                default:
8079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    throw new RuntimeException("Unsupported Encoding Scheme");
8089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
8099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        boolean isUserIDRequired = false;
8129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        boolean isFullAccess = true;
8139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (option != null) {
8149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if ((option[0] & 0x01) != 0) {
8159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                isUserIDRequired = true;
8169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
8179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if ((option[0] & 0x02) != 0) {
8199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                isFullAccess = false;
8209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
8219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        PasswordAuthentication result = null;
8249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        header.authChall = null;
8259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
8279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            result = authenticator.onAuthenticationChallenge(realm, isUserIDRequired, isFullAccess);
8289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
8299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
8309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
8339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * If no password is provided then we not resent the request
8349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
8359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (result == null) {
8369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
8379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] password = result.getPassword();
8409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (password == null) {
8419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
8429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] userName = result.getUserName();
8459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
8479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Create the authentication response header. It includes 1 required and
8489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * 2 option tag length value triples. The required triple has a tag of
8499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * 0x00 and is the response digest. The first optional tag is 0x01 and
8509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * represents the user ID. If no user ID is provided, then no user ID
8519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * will be sent. The second optional tag is 0x02 and is the challenge
8529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * that was received. This will always be sent
8539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
8549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (userName != null) {
8559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            header.authResp = new byte[38 + userName.length];
8569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            header.authResp[36] = (byte)0x01;
8579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            header.authResp[37] = (byte)userName.length;
8589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(userName, 0, header.authResp, 38, userName.length);
8599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
8609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            header.authResp = new byte[36];
8619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Create the secret String
8649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] digest = new byte[challenge.length + password.length + 1];
8659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(challenge, 0, digest, 0, challenge.length);
8669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Insert colon between challenge and password
8679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        digest[challenge.length] = (byte)0x3A;
8689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(password, 0, digest, challenge.length + 1, password.length);
8699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Add the Response Digest
8719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        header.authResp[0] = (byte)0x00;
8729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        header.authResp[1] = (byte)0x10;
8739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8742e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.authResp, 2, 16);
8759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Add the challenge
8779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        header.authResp[18] = (byte)0x02;
8789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        header.authResp[19] = (byte)0x10;
8799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(challenge, 0, header.authResp, 20, 16);
8809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return true;
8829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
8839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
8849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
8859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Called when the server received an authentication response header. This
8869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * will cause the authenticator to handle the authentication response.
8879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
8889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @param authResp
8899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *            the authentication response
8909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *
8919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return <code>true</code> if the response passed; <code>false</code> if
8929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *         the response failed
8939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
8949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    protected boolean handleAuthResp(byte[] authResp) {
8959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (authenticator == null) {
8969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
8979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
8989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // get the correct password from the application
8992e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] correctPassword = authenticator.onAuthenticationResponse(ObexHelper.getTagValue(
9009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                (byte)0x01, authResp));
9019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (correctPassword == null) {
9029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return false;
9039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] temp = new byte[correctPassword.length + 16];
9069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(challengeDigest, 0, temp, 0, 16);
9089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length);
9099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9102e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] correctResponse = ObexHelper.computeMd5Hash(temp);
9112e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp);
9129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // compare the MD5 hash array .
9149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        for (int i = 0; i < 16; i++) {
9159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (correctResponse[i] != actualResponse[i]) {
9169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                return false;
9179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
9189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
9199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
9209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return true;
9219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
9229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
923