From 2e0da96e757a977154063f980d3f4e1abd41cf09 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Tue, 30 Jun 2009 16:28:54 -0700 Subject: Obex library cleanup, first pass. o Add Android.mk file. o Add @hide so it is not exposed in the public API. It is not yet in shape. o Prefer @throws to @exception o Do not use @version. This is meaningless in Android. o Prefer classes 'final' unless explicitly allowing inheritance (See "Effective Java" item 15) o Prefer CamelCaps java naming even for acronyms (OBEXHelper -> ObexHelper) o Use the built-in MD5 library. o Move ObexConstants into ObexHelper. o Remove unused variables. o Prefer stricter access priveleges. Most importantly, avoid public fields. o Don't use 'import java.io.*'. Name each class explicitly. o Delete commented out code. If its not used then remove it. --- obex/Android.mk | 9 + obex/javax/obex/ApplicationParameter.java | 23 +- obex/javax/obex/Authenticator.java | 2 +- obex/javax/obex/BaseStream.java | 12 +- obex/javax/obex/ClientOperation.java | 104 +-- obex/javax/obex/ClientSession.java | 80 +- obex/javax/obex/HeaderSet.java | 29 +- obex/javax/obex/OBEXConstants.java | 74 -- obex/javax/obex/OBEXHelper.java | 1326 --------------------------- obex/javax/obex/ObexHelper.java | 995 ++++++++++++++++++++ obex/javax/obex/ObexSession.java | 11 +- obex/javax/obex/ObexTransport.java | 3 +- obex/javax/obex/Operation.java | 14 +- obex/javax/obex/PasswordAuthentication.java | 2 +- obex/javax/obex/PrivateInputStream.java | 13 +- obex/javax/obex/PrivateOutputStream.java | 12 +- obex/javax/obex/ResponseCodes.java | 6 +- obex/javax/obex/ServerOperation.java | 73 +- obex/javax/obex/ServerRequestHandler.java | 4 +- obex/javax/obex/ServerSession.java | 89 +- obex/javax/obex/SessionNotifier.java | 18 +- 21 files changed, 1235 insertions(+), 1664 deletions(-) create mode 100644 obex/Android.mk delete mode 100644 obex/javax/obex/OBEXConstants.java delete mode 100644 obex/javax/obex/OBEXHelper.java create mode 100644 obex/javax/obex/ObexHelper.java (limited to 'obex') diff --git a/obex/Android.mk b/obex/Android.mk new file mode 100644 index 0000000..fbfe9be --- /dev/null +++ b/obex/Android.mk @@ -0,0 +1,9 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_MODULE:= javax.obex + +include $(BUILD_JAVA_LIBRARY) diff --git a/obex/javax/obex/ApplicationParameter.java b/obex/javax/obex/ApplicationParameter.java index 8ed4ca6..e808360 100644 --- a/obex/javax/obex/ApplicationParameter.java +++ b/obex/javax/obex/ApplicationParameter.java @@ -32,12 +32,14 @@ package javax.obex; -public class ApplicationParameter { - private int max_length_ini = 1000; +/** + * @hide + */ +public final class ApplicationParameter { private byte[] b_array; - private int length; + private int max_length = 1000; public static class TRIPLET_TAGID { public static final byte ORDER_TAGID = 0x01; @@ -46,7 +48,8 @@ public class ApplicationParameter { public static final byte SEARCH_ATTRIBUTE_TAGID = 0x03; - public static final byte MAXLISTCOUNT_TAGID = 0x04;//if equals to "0", PSE only reply number of contacts + // if equals to "0", PSE only reply number of contacts + public static final byte MAXLISTCOUNT_TAGID = 0x04; public static final byte LISTSTARTOFFSET_TAGID = 0x05; @@ -54,9 +57,11 @@ public class ApplicationParameter { public static final byte FORMAT_TAGID = 0x07; - public static final byte PHONEBOOKSIZE_TAGID = 0x08;//only used if max list count = 0 + // only used if max list count = 0 + public static final byte PHONEBOOKSIZE_TAGID = 0x08; - public static final byte NEWMISSEDCALLS_TAGID = 0x09;//only used in "mch" in response + // only used in "mch" in response + public static final byte NEWMISSEDCALLS_TAGID = 0x09; } public static class TRIPLET_VALUE { @@ -110,16 +115,16 @@ public class ApplicationParameter { } */ public ApplicationParameter() { - b_array = new byte[max_length_ini]; + b_array = new byte[max_length]; length = 0; } public void addAPPHeader(byte tag, byte len, byte[] value) { - if ((length + len + 2) > max_length_ini) { + if ((length + len + 2) > max_length) { byte[] array_tmp = new byte[length + 4 * len]; System.arraycopy(b_array, 0, array_tmp, 0, length); b_array = array_tmp; - max_length_ini = length + 4 * len; + max_length = length + 4 * len; } b_array[length++] = tag; b_array[length++] = len; diff --git a/obex/javax/obex/Authenticator.java b/obex/javax/obex/Authenticator.java index a1729f8..90da7ba 100644 --- a/obex/javax/obex/Authenticator.java +++ b/obex/javax/obex/Authenticator.java @@ -81,7 +81,7 @@ package javax.obex; * ServerRequestHandler that failed authentication. The * connection is not closed if authentication failed. * - * @version 0.3 November 28, 2008 + * @hide */ public interface Authenticator { diff --git a/obex/javax/obex/BaseStream.java b/obex/javax/obex/BaseStream.java index ffd0b63..67581bf 100644 --- a/obex/javax/obex/BaseStream.java +++ b/obex/javax/obex/BaseStream.java @@ -32,20 +32,20 @@ package javax.obex; -import java.io.*; +import java.io.IOException; /** * This interface defines the methods needed by a parent that uses the * PrivateInputStream and PrivateOutputStream objects defined in this package. * - * @version 0.3 November 28, 2008 + * @hide */ public interface BaseStream { /** * Verifies that this object is still open. * - * @exception IOException if the object is closed + * @throws IOException if the object is closed */ public void ensureOpen() throws IOException; @@ -53,7 +53,7 @@ public interface BaseStream { * Verifies that additional information may be sent. In other words, the * operation is not done. * - * @exception IOException if the operation is completed + * @throws IOException if the operation is completed */ public void ensureNotDone() throws IOException; @@ -67,7 +67,7 @@ public interface BaseStream { * @return true if the operation was completed; * false if no operation took place * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException; @@ -77,7 +77,7 @@ public interface BaseStream { * @param inStream true if the input stream is closed; * false if the output stream is closed * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public void streamClosed(boolean inStream) throws IOException; } diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java index dc4e944..1bd1367 100644 --- a/obex/javax/obex/ClientOperation.java +++ b/obex/javax/obex/ClientOperation.java @@ -43,9 +43,9 @@ import java.io.ByteArrayOutputStream; * This class implements the Operation interface. It will read * and write data via puts and gets. * - * @version 0.3 November 28, 2008 + * @hide */ -public class ClientOperation implements Operation, BaseStream { +public final class ClientOperation implements Operation, BaseStream { /** * Defines the basic packet length used by OBEX. Event OBEX packet has the @@ -99,7 +99,7 @@ public class ClientOperation implements Operation, BaseStream { * @param type true if this is a get request; * falseHeaderSet * object created by calling createHeaderSet in a * ClientSession object @@ -200,7 +200,7 @@ public class ClientOperation implements Operation, BaseStream { public synchronized int getResponseCode() throws IOException { //avoid dup validateConnection if ((replyHeaders.responseCode == -1) - || (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { + || (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) { validateConnection(); } @@ -259,7 +259,7 @@ public class ClientOperation implements Operation, BaseStream { * * @return an input stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public InputStream openInputStream() throws IOException { // TODO: this mode is not set yet. @@ -290,7 +290,7 @@ public class ClientOperation implements Operation, BaseStream { * * @return an input stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); @@ -301,7 +301,7 @@ public class ClientOperation implements Operation, BaseStream { * * @return an output stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public OutputStream openOutputStream() throws IOException { // TODO: this mode is not set yet. @@ -332,7 +332,7 @@ public class ClientOperation implements Operation, BaseStream { * * @return an output stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); @@ -341,7 +341,7 @@ public class ClientOperation implements Operation, BaseStream { /** * Closes the connection and ends the transaction * - * @exception IOException if the operation has already ended or is closed + * @throws IOException if the operation has already ended or is closed */ public void close() throws IOException { isClosed = true; @@ -357,7 +357,7 @@ public class ClientOperation implements Operation, BaseStream { * * @return the headers received during this Operation * - * @exception IOException if this Operation has been closed + * @throws IOException if this Operation has been closed */ public HeaderSet getReceivedHeaders() throws IOException { ensureOpen(); @@ -371,13 +371,13 @@ public class ClientOperation implements Operation, BaseStream { * * @param headers the headers to send in the next message * - * @exception IOException if this Operation has been closed + * @throws IOException if this Operation has been closed * or the transaction has ended and no further messages will be exchanged * - * @exception IllegalArgumentException if headers was not created + * @throws IllegalArgumentException if headers was not created * by a call to ServerRequestHandler.createHeaderSet() * - * @exception NullPointerException if headers is null + * @throws NullPointerException if headers is null */ public void sendHeaders(HeaderSet headers) throws IOException { ensureOpen(); @@ -404,14 +404,14 @@ public class ClientOperation implements Operation, BaseStream { * @return true if the transaction should end; * false if the transaction should not end * - * @exception IOException if an IO error occurred + * @throws IOException if an IO error occurred */ private boolean readResponse() throws IOException { replyHeaders.responseCode = socketInput.read(); int packetLength = socketInput.read(); packetLength = (packetLength << 8) + socketInput.read(); - if (packetLength > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) { if (exceptionMessage != null) { abort(); } @@ -425,7 +425,7 @@ public class ClientOperation implements Operation, BaseStream { if (readLength != dataLength) { throw new IOException("Received a packet without data as decalred length"); } - byte[] body = OBEXHelper.updateHeaderSet(replyHeaders, data); + byte[] body = ObexHelper.updateHeaderSet(replyHeaders, data); if (body != null) { privateInput.writeBytes(body, 1); @@ -442,7 +442,7 @@ public class ClientOperation implements Operation, BaseStream { } } - if (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) { return true; } else { return false; @@ -453,7 +453,7 @@ public class ClientOperation implements Operation, BaseStream { * Verifies that additional information may be sent. In other words, the * operation is not done. * - * @exception IOException if the operation is completed + * @throws IOException if the operation is completed */ public void ensureNotDone() throws IOException { if (isDone) { @@ -464,7 +464,7 @@ public class ClientOperation implements Operation, BaseStream { /** * Verifies that the connection is open and no exceptions should be thrown. * - * @exception IOException if an exception needs to be thrown + * @throws IOException if an exception needs to be thrown */ public void ensureOpen() throws IOException { parent.ensureOpen(); @@ -480,7 +480,7 @@ public class ClientOperation implements Operation, BaseStream { /** * Verifies that the connection is open and the proper data has been read. * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ private void validateConnection() throws IOException { ensureOpen(); @@ -499,13 +499,13 @@ public class ClientOperation implements Operation, BaseStream { * @return true if there is more data to send; * false if there is no more data to send * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ protected boolean sendRequest(int type) throws IOException { boolean returnValue = false; ByteArrayOutputStream out = new ByteArrayOutputStream(); int bodyLength = -1; - byte[] headerArray = OBEXHelper.createHeader(requestHeaders, true); + byte[] headerArray = ObexHelper.createHeader(requestHeaders, true); if (privateOutput != null) { bodyLength = privateOutput.size(); } @@ -525,7 +525,7 @@ public class ClientOperation implements Operation, BaseStream { while (end != headerArray.length) { //split the headerArray - end = OBEXHelper.findHeaderEnd(headerArray, start, maxPacketSize + end = ObexHelper.findHeaderEnd(headerArray, start, maxPacketSize - BASE_PACKET_LENGTH); // can not split if (end == -1) { @@ -551,7 +551,7 @@ public class ClientOperation implements Operation, BaseStream { return false; } - if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) { return false; } @@ -642,7 +642,7 @@ public class ClientOperation implements Operation, BaseStream { * initial request. If the response takes more then one packet, a thread * will be started to handle additional requests * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ private synchronized void startProcessing() throws IOException { @@ -653,33 +653,33 @@ public class ClientOperation implements Operation, BaseStream { if (isGet) { if (!isDone) { - replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; - while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { + replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE; + while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) { more = sendRequest(0x03); } - if (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) { parent.sendRequest(0x83, null, replyHeaders, privateInput); } - if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) { isDone = true; } } } else { if (!isDone) { - replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; - while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { + replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE; + while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) { more = sendRequest(0x02); } } - if (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) { parent.sendRequest(0x82, null, replyHeaders, privateInput); } - if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) { isDone = true; } } @@ -692,7 +692,7 @@ public class ClientOperation implements Operation, BaseStream { * empty packet or not send anything if there is no data to send * @param inStream true if the stream is input stream or * is output stream - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream) throws IOException { @@ -704,7 +704,7 @@ public class ClientOperation implements Operation, BaseStream { /* * Determine if that was not the last packet in the operation */ - if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) { isDone = true; } @@ -727,7 +727,7 @@ public class ClientOperation implements Operation, BaseStream { if ((!inStream) && (!isDone)) { // to deal with outputstream in put operation if (replyHeaders.responseCode == -1) { - replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; + replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE; } sendRequest(0x02); return true; @@ -749,7 +749,7 @@ public class ClientOperation implements Operation, BaseStream { * @param inStream true if the input stream is closed; * false if the output stream is closed * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public void streamClosed(boolean inStream) throws IOException { if (!isGet) { @@ -759,16 +759,16 @@ public class ClientOperation implements Operation, BaseStream { boolean more = true; if ((privateOutput != null) && (privateOutput.size() <= 0)) { - byte[] headerArray = OBEXHelper.createHeader(requestHeaders, false); + byte[] headerArray = ObexHelper.createHeader(requestHeaders, false); if (headerArray.length <= 0) more = false; } // If have not sent any data so send all now if (replyHeaders.responseCode == -1) { - replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; + replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE; } - while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { + while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) { more = sendRequest(0x02); } @@ -777,7 +777,7 @@ public class ClientOperation implements Operation, BaseStream { * only have a single reply to send. so we don't need the while * loop. */ - while (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { + while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) { sendRequest(0x82); } @@ -794,15 +794,15 @@ public class ClientOperation implements Operation, BaseStream { // Have not sent any data so send it all now if (replyHeaders.responseCode == -1) { - replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; + replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE; } - while (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { + while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) { if (!sendRequest(0x83)) { break; } } - while (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { + while (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE) { parent.sendRequest(0x83, null, replyHeaders, privateInput); } isDone = true; @@ -813,7 +813,7 @@ public class ClientOperation implements Operation, BaseStream { boolean more = true; if ((privateOutput != null) && (privateOutput.size() <= 0)) { - byte[] headerArray = OBEXHelper.createHeader(requestHeaders, false); + byte[] headerArray = ObexHelper.createHeader(requestHeaders, false); if (headerArray.length <= 0) more = false; } @@ -824,13 +824,13 @@ public class ClientOperation implements Operation, BaseStream { if ((privateOutput != null) && (privateOutput.size() <= 0)) more = false; - replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; - while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { + replyHeaders.responseCode = ObexHelper.OBEX_HTTP_CONTINUE; + while ((more) && (replyHeaders.responseCode == ObexHelper.OBEX_HTTP_CONTINUE)) { more = sendRequest(0x03); } sendRequest(0x83); // parent.sendRequest(0x83, null, replyHeaders, privateInput); - if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { + if (replyHeaders.responseCode != ObexHelper.OBEX_HTTP_CONTINUE) { isDone = true; } diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java index c624c30..bdbd699 100644 --- a/obex/javax/obex/ClientSession.java +++ b/obex/javax/obex/ClientSession.java @@ -41,17 +41,16 @@ import java.io.OutputStream; * This class implements the Operation interface. It will read * and write data via puts and gets. * - * @version 0.3 November 28, 2008 + * @hide */ public class ClientSession implements ObexSession { - //protected StreamConnection client; protected Authenticator authenticator; protected boolean connectionOpen = false; - protected boolean isConnected; // Determines if an OBEX layer connection + // Determines if an OBEX layer connection has been established + protected boolean isConnected; - // has been established private byte[] connectionID = null; byte[] challengeDigest = null; @@ -62,8 +61,6 @@ public class ClientSession implements ObexSession { protected ObexTransport trans = null; - public int mode; - /* * The max Packet size must be at least 256 according to the OBEX * specification. @@ -87,29 +84,6 @@ public class ClientSession implements ObexSession { } - /* comment out as not used internally - public boolean isClosed() { - // if (client instanceof BTConnection) - // return ((BTConnection)client).isClosed(); - // else - return false; - } - - public int getConnectionHandle() { - //if (client instanceof BTConnection) - // return ((BTConnection)client).getConnectionHandle(); - //else - return -1; - } - - public RemoteDevice getRemoteDevice() { - if (client instanceof BTConnection) - return ((BTConnection)client).getRemoteDevice(); - else - return null; - } - */ - public HeaderSet connect(HeaderSet header) throws java.io.IOException { ensureOpen(); if (isConnected) { @@ -130,7 +104,7 @@ public class ClientSession implements ObexSession { challengeDigest = new byte[16]; System.arraycopy((header).nonce, 0, challengeDigest, 0, 16); } - head = OBEXHelper.createHeader(header, false); + head = ObexHelper.createHeader(header, false); totalLength += head.length; } /* @@ -147,14 +121,14 @@ public class ClientSession implements ObexSession { // handle the length and 0x80. requestPacket[0] = (byte)0x10; requestPacket[1] = (byte)0x00; - requestPacket[2] = (byte)(OBEXConstants.MAX_PACKET_SIZE_INT >> 8); - requestPacket[3] = (byte)(OBEXConstants.MAX_PACKET_SIZE_INT & 0xFF); + requestPacket[2] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8); + requestPacket[3] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF); if (head != null) { System.arraycopy(head, 0, requestPacket, 4, head.length); } // check with local max packet size - if ((requestPacket.length + 3) > OBEXConstants.MAX_PACKET_SIZE_INT) { + if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) { throw new IOException("Packet size exceeds max packet size"); } @@ -207,7 +181,6 @@ public class ClientSession implements ObexSession { System.arraycopy(connectionID, 0, (header).connectionID, 0, 4); } - // this.mode = javax.microedition.io.Connector.READ ; return new ClientOperation(input, maxPacketSize, this, header, true); } @@ -218,7 +191,7 @@ public class ClientSession implements ObexSession { if ((id < 0) || (id > 0xFFFFFFFFL)) { throw new IllegalArgumentException("Connection ID is not in a valid range"); } - connectionID = OBEXHelper.convertToByteArray(id); + connectionID = ObexHelper.convertToByteArray(id); } public HeaderSet createHeaderSet() { @@ -258,7 +231,7 @@ public class ClientSession implements ObexSession { (header).connectionID = new byte[4]; System.arraycopy(connectionID, 0, (header).connectionID, 0, 4); } - head = OBEXHelper.createHeader(header, false); + head = ObexHelper.createHeader(header, false); if ((head.length + 3) > maxPacketSize) { throw new IOException("Packet size exceeds max packet size"); @@ -298,7 +271,7 @@ public class ClientSession implements ObexSession { if (connectionID == null) { return -1; } - return OBEXHelper.convertToLong(connectionID); + return ObexHelper.convertToLong(connectionID); } public Operation put(HeaderSet header) throws java.io.IOException { @@ -331,7 +304,6 @@ public class ClientSession implements ObexSession { System.arraycopy(connectionID, 0, (header).connectionID, 0, 4); } - // this.mode = javax.microedition.io.Connector.WRITE ; return new ClientOperation(input, maxPacketSize, this, header, false); } @@ -380,7 +352,7 @@ public class ClientSession implements ObexSession { System.arraycopy(connectionID, 0, (header).connectionID, 0, 4); } - head = OBEXHelper.createHeader(header, false); + head = ObexHelper.createHeader(header, false); totalLength += head.length; if (totalLength > maxPacketSize) { @@ -436,7 +408,7 @@ public class ClientSession implements ObexSession { /** * Verifies that the connection is open. * - * @exception IOException if the connection is closed + * @throws IOException if the connection is closed */ public synchronized void ensureOpen() throws IOException { if (!connectionOpen) { @@ -476,13 +448,13 @@ public class ClientSession implements ObexSession { * return true if the operation completed successfully; * false if an authentication response failed to pass * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public boolean sendRequest(int code, byte[] head, HeaderSet headers, PrivateInputStream privateInput) throws IOException { //check header length with local max size if (head != null) { - if ((head.length + 3) > OBEXConstants.MAX_PACKET_SIZE_INT) { + if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) { throw new IOException("header too large "); } } @@ -509,7 +481,7 @@ public class ClientSession implements ObexSession { int length = ((input.read() << 8) | (input.read())); - if (length > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (length > ObexHelper.MAX_PACKET_SIZE_INT) { throw new IOException("Packet received exceeds packet size limit"); } if (length > 3) { @@ -520,8 +492,8 @@ public class ClientSession implements ObexSession { maxPacketSize = (input.read() << 8) + input.read(); //check with local max size - if (maxPacketSize > OBEXConstants.MAX_PACKET_SIZE_INT) { - maxPacketSize = OBEXConstants.MAX_PACKET_SIZE_INT; + if (maxPacketSize > ObexHelper.MAX_PACKET_SIZE_INT) { + maxPacketSize = ObexHelper.MAX_PACKET_SIZE_INT; } if (length > 7) { @@ -547,7 +519,7 @@ public class ClientSession implements ObexSession { } } - byte[] body = OBEXHelper.updateHeaderSet(headers, data); + byte[] body = ObexHelper.updateHeaderSet(headers, data); if ((privateInput != null) && (body != null)) { privateInput.writeBytes(body, 1); } @@ -610,9 +582,9 @@ public class ClientSession implements ObexSession { * granted. The tag 0x02 is the realm, which provides a description of * which user name and password to use. */ - byte[] challenge = OBEXHelper.getTagValue((byte)0x00, header.authChall); - byte[] option = OBEXHelper.getTagValue((byte)0x01, header.authChall); - byte[] description = OBEXHelper.getTagValue((byte)0x02, header.authChall); + byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall); + byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall); + byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall); String realm = ""; if (description != null) { @@ -635,7 +607,7 @@ public class ClientSession implements ObexSession { case 0xFF: // UNICODE Encoding - realm = OBEXHelper.convertToUnicode(realmString, false); + realm = ObexHelper.convertToUnicode(realmString, false); break; case 0x02: @@ -728,7 +700,7 @@ public class ClientSession implements ObexSession { header.authResp[0] = (byte)0x00; header.authResp[1] = (byte)0x10; - byte[] responseDigest = OBEXHelper.computeMD5Hash(digest); + byte[] responseDigest = ObexHelper.computeMd5Hash(digest); System.arraycopy(responseDigest, 0, header.authResp, 2, 16); // Add the challenge @@ -753,7 +725,7 @@ public class ClientSession implements ObexSession { return false; } - byte[] correctPassword = authenticator.onAuthenticationResponse(OBEXHelper.getTagValue( + byte[] correctPassword = authenticator.onAuthenticationResponse(ObexHelper.getTagValue( (byte)0x01, authResp)); if (correctPassword == null) { return false; @@ -763,8 +735,8 @@ public class ClientSession implements ObexSession { System.arraycopy(challengeDigest, 0, temp, 0, 16); System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length); - byte[] correctResponse = OBEXHelper.computeMD5Hash(temp); - byte[] actualResponse = OBEXHelper.getTagValue((byte)0x00, authResp); + byte[] correctResponse = ObexHelper.computeMd5Hash(temp); + byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp); for (int i = 0; i < 16; i++) { if (correctResponse[i] != actualResponse[i]) { return false; diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java index 07abe15..5dddf8f 100644 --- a/obex/javax/obex/HeaderSet.java +++ b/obex/javax/obex/HeaderSet.java @@ -32,14 +32,16 @@ package javax.obex; -import java.io.*; -import java.util.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Calendar; +import java.util.Random; /** * This class implements the javax.obex.HeaderSet interface for OBEX over * RFCOMM. * - * @version 0.3 November 28, 2008 + * @hide */ public final class HeaderSet { @@ -159,9 +161,8 @@ public final class HeaderSet { private byte[] who; // length prefixed byte sequence - private byte[] appParam; // byte sequence of the form tag length + private byte[] appParam; // byte sequence of the form tag length value - //value public byte[] authChall; // The authentication challenge header public byte[] authResp; // The authentication response header @@ -178,11 +179,11 @@ public final class HeaderSet { private Long[] integerUserDefined; // 4 byte unsigned integer - public int responseCode; + /*package*/ int responseCode; - public byte[] nonce; + /*package*/ byte[] nonce; - private Random random; + private final Random random; /** * Creates new HeaderSet object. @@ -209,7 +210,7 @@ public final class HeaderSet { * * @param headerValue the value of the header identifier * - * @exception IllegalArgumentException if the header identifier provided is + * @throws IllegalArgumentException if the header identifier provided is * not one defined in this interface or a user-defined header; if the type of * headerValue is not the correct Java type as defined in the * description of this interface\ @@ -406,10 +407,10 @@ public final class HeaderSet { * header identifier specified is not part of this HeaderSet * object * - * @exception IllegalArgumentException if the headerID is not + * @throws IllegalArgumentException if the headerID is not * one defined in this interface or any of the user-defined headers * - * @exception IOException if an error occurred in the transport layer during + * @throws IOException if an error occurred in the transport layer during * the operation or if the connection has been closed */ public Object getHeader(int headerID) throws IOException { @@ -471,7 +472,7 @@ public final class HeaderSet { * @return the array of headers that are set in this object or * null if no headers are available * - * @exception IOException if an error occurred in the transport layer during + * @throws IOException if an error occurred in the transport layer during * the operation or the connection has been closed */ public int[] getHeaderList() throws IOException { @@ -580,7 +581,7 @@ public final class HeaderSet { nonce[i] = (byte)random.nextInt(); } - authChall = OBEXHelper.computeAuthenticationChallenge(nonce, realm, access, userID); + authChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } @@ -594,7 +595,7 @@ public final class HeaderSet { * * @return the response code retrieved from the server * - * @exception IOException if an error occurred in the transport layer during + * @throws IOException if an error occurred in the transport layer during * the transaction; if this method is called on a HeaderSet * object created by calling createHeaderSet() in a * ClientSession object; if this object was created by an OBEX diff --git a/obex/javax/obex/OBEXConstants.java b/obex/javax/obex/OBEXConstants.java deleted file mode 100644 index 2da5f30..0000000 --- a/obex/javax/obex/OBEXConstants.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2008-2009, Motorola, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of the Motorola, Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package javax.obex; - -/** - * This class implements the Operation interface. It will read - * and write data via puts and gets. - * - * @version 0.3 November 28, 2008 - */ -public class OBEXConstants { - /** - * Defines the OBEX CONTINUE response code. - *

- * The value of OBEX_HTTP_CONTINUE is 0x90 (144). - */ - public static final int OBEX_HTTP_CONTINUE = 0x90; - - /** - * The maximum packet size for OBEX packets that this client can handle. - * At present, this must be changed for each port. - * - * OPTIMIZATION: The max packet size should be the Max incoming MTU minus - * OPTIMIZATION: L2CAP package headers and RFCOMM package headers. - * - * OPTIMIZATION: Retrieve the max incoming MTU from - * OPTIMIZATION: LocalDevice.getProperty(). - */ - /** android note - * set as 0xFFFE to match remote MPS - */ - //public static final byte[] MAX_PACKET_SIZE = {0x01, 0x00}; // To be removed - //public static final int MAX_PACKET_SIZE_INT = 667*6;//0x0100; - public static final int MAX_PACKET_SIZE_INT = 0xFFFE; - - /** - * The number of server parser threads that may be active at one time. - * This should be changed for each port. - * - * OPTIMIZATION: Retrieve this value by a native call to the KOSI layer. - */ - public static final int MAX_PARSER_THREADS = 5; - -} diff --git a/obex/javax/obex/OBEXHelper.java b/obex/javax/obex/OBEXHelper.java deleted file mode 100644 index 5c413af..0000000 --- a/obex/javax/obex/OBEXHelper.java +++ /dev/null @@ -1,1326 +0,0 @@ -/* - * Copyright (c) 2008-2009, Motorola, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of the Motorola, Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package javax.obex; - -import java.io.*; -import java.util.*; - -/** - * This class defines a set of helper methods for the implementation of OBEX. - * - * @version 0.3 November 28, 2008 - */ -public class OBEXHelper { - - /** - * Creates new OBEXHelper - */ - private OBEXHelper() { - } - - private static final String TAG = "OBEXHelper"; - - /** - * Updates the HeaderSet with the headers received in the byte array - * provided. Invalid headers are ignored. - *

- * The first two bits of an OBEX Header specifies the type of object that - * is being sent. The table below specifies the meaning of the high - * bits. - * - * - * - * - * - * - *
Bits 8 and 7ValueDescription
000x00Null Terminated Unicode text, prefixed - * with 2 byte unsigned integer
010x40Byte Sequence, length prefixed with - * 2 byte unsigned integer
100x801 byte quantity
110xC04 byte quantity - transmitted in - * network byte order (high byte first
- * This method uses the information in this table to determine the type of - * Java object to create and passes that object with the full header - * to setHeader() to update the HeaderSet object. Invalid headers will - * cause an exception to be thrown. When it is thrown, it is ignored. - * - * @param header the HeaderSet to update - * - * @param headerArray the byte array containing headers - * - * @return the result of the last start body or end body header provided; - * the first byte in the result will specify if a body or end of body is - * received - * - * @exception IOException if an invalid header was found - */ - public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException { - int index = 0; - int length = 0; - int headerID; - byte[] value = null; - byte[] body = null; - HeaderSet headerImpl = header; - try { - while (index < headerArray.length) { - headerID = 0xFF & headerArray[index]; - switch (headerID & (0xC0)) { - - /* - * 0x00 is a unicode null terminate string with the first - * two bytes after the header identifier being the length - */ - case 0x00: - // Fall through - /* - * 0x40 is a byte sequence with the first - * two bytes after the header identifier being the length - */ - case 0x40: - boolean trimTail = true; - index++; - length = 0xFF & headerArray[index]; - length = length << 8; - index++; - length += 0xFF & headerArray[index]; - length -= 3; - index++; - value = new byte[length]; - System.arraycopy(headerArray, index, value, 0, length); - if (length == 0 || (length > 0 && (value[length - 1] != 0))) { - trimTail = false; - } - switch (headerID) { - case HeaderSet.TYPE: - try { - // Remove trailing null - if (trimTail == false) { - headerImpl.setHeader(headerID, new String(value, 0, - value.length, "ISO8859_1")); - } else { - headerImpl.setHeader(headerID, new String(value, 0, - value.length - 1, "ISO8859_1")); - } - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("ISO8859_1 is not supported" - + e.getMessage()); - } - break; - - // This is the constant for the authentication challenge header - // This header does not have a constant defined in the Java - // OBEX API - case 0x4D: - headerImpl.authChall = new byte[length]; - System.arraycopy(headerArray, index, headerImpl.authChall, 0, - length); - break; - - // This is the constant for the authentication response header - // This header does not have a constant defined in the Java - // OBEX API - case 0x4E: - headerImpl.authResp = new byte[length]; - System - .arraycopy(headerArray, index, headerImpl.authResp, 0, - length); - break; - - /* - * These two case statements are for the body (0x48) - * and end of body (0x49) headers. - */ - case 0x48: - /* Fall Through */ - case 0x49: - body = new byte[length + 1]; - body[0] = (byte)headerID; - System.arraycopy(headerArray, index, body, 1, length); - break; - - case HeaderSet.TIME_ISO_8601: - try { - String dateString = new String(value, "ISO8859_1"); - Calendar temp = Calendar.getInstance(); - if ((dateString.length() == 16) - && (dateString.charAt(15) == 'Z')) { - temp.setTimeZone(TimeZone.getTimeZone("UTC")); - } - temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring( - 0, 4))); - temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring( - 4, 6))); - temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString - .substring(6, 8))); - temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString - .substring(9, 11))); - temp.set(Calendar.MINUTE, Integer.parseInt(dateString - .substring(11, 13))); - temp.set(Calendar.SECOND, Integer.parseInt(dateString - .substring(13, 15))); - headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("ISO8859_1 is not supported" - + e.getMessage()); - } catch (Exception e) { - throw new IOException( - "Time Header does not follow ISO 8601 standard"); - } - break; - - default: - try { - if ((headerID & 0xC0) == 0x00) { - headerImpl.setHeader(headerID, OBEXHelper.convertToUnicode( - value, true)); - } else { - headerImpl.setHeader(headerID, value); - } - } catch (Exception e) { - // Not a valid header so ignore - } - } - - index += length; - break; - - /* - * 0x80 is a byte header. The only valid byte headers are - * the 16 user defined byte headers. - */ - case 0x80: - index++; - try { - headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index])); - } catch (Exception e) { - // Not a valid header so ignore - } - index++; - break; - - /* - * 0xC0 is a 4 byte unsigned integer header and with the - * exception of TIME_4_BYTE will be converted to a Long - * and added. - */ - case 0xC0: - index++; - value = new byte[4]; - System.arraycopy(headerArray, index, value, 0, 4); - try { - if (headerID != HeaderSet.TIME_4_BYTE) { - // Determine if it is a connection ID. These - // need to be handled differently - if (headerID == 0xCB) { - headerImpl.connectionID = new byte[4]; - System.arraycopy(value, 0, headerImpl.connectionID, 0, 4); - } else { - headerImpl.setHeader(headerID, Long - .valueOf(convertToLong(value))); - } - } else { - Calendar temp = Calendar.getInstance(); - temp.setTime(new Date(convertToLong(value) * 1000L)); - headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp); - } - } catch (Exception e) { - // Not a valid header so ignore - throw new IOException("Header was not formatted properly"); - } - index += 4; - break; - } - - } - } catch (IOException e) { - throw new IOException("Header was not formatted properly"); - } - - return body; - } - - /** - * Creates the header part of OBEX packet based on the header provided. - * - * OPTIMIZATION: Could use getHeaderList() to get the array of headers to - * OPTIMIZATION: include and then use the high two bits to determine the - * OPTIMIZATION: the type of the object and construct the byte array from - * OPTIMIZATION: that. This will make the size smaller. - * - * @param head the header used to construct the byte array - * - * @param nullOut true if the header should be set to - * null once it is added to the array or false - * if it should not be nulled out - * - * @return the header of an OBEX packet - */ - public static byte[] createHeader(HeaderSet head, boolean nullOut) { - Long intHeader = null; - String stringHeader = null; - Calendar dateHeader = null; - Byte byteHeader = null; - StringBuffer buffer = null; - byte[] value = null; - byte[] result = null; - byte[] lengthArray = new byte[2]; - int length; - HeaderSet headImpl = null; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - if (!(head instanceof HeaderSet)) { - throw new IllegalArgumentException("Header not created by createHeaderSet"); - } - headImpl = head; - - try { - /* - * Determine if there is a connection ID to send. If there is, - * then it should be the first header in the packet. - */ - if ((headImpl.connectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) { - - out.write((byte)0xCB); - out.write(headImpl.connectionID); - } - - // Count Header - intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT); - if (intHeader != null) { - out.write((byte)HeaderSet.COUNT); - value = OBEXHelper.convertToByteArray(intHeader.longValue()); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.COUNT, null); - } - } - - // Name Header - stringHeader = (String)headImpl.getHeader(HeaderSet.NAME); - if (stringHeader != null) { - out.write((byte)HeaderSet.NAME); - value = OBEXHelper.convertToUnicodeByteArray(stringHeader); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.NAME, null); - } - } - - // Type Header - stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE); - if (stringHeader != null) { - out.write((byte)HeaderSet.TYPE); - try { - value = stringHeader.getBytes("ISO8859_1"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("Unsupported Encoding Scheme: " + e.getMessage()); - } - - length = value.length + 4; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - out.write(0x00); - if (nullOut) { - headImpl.setHeader(HeaderSet.TYPE, null); - } - } - - // Length Header - intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH); - if (intHeader != null) { - out.write((byte)HeaderSet.LENGTH); - value = OBEXHelper.convertToByteArray(intHeader.longValue()); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.LENGTH, null); - } - } - - // Time ISO Header - dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601); - if (dateHeader != null) { - - /* - * The ISO Header should take the form YYYYMMDDTHHMMSSZ. The - * 'Z' will only be included if it is a UTC time. - */ - buffer = new StringBuffer(); - int temp = dateHeader.get(Calendar.YEAR); - for (int i = temp; i < 1000; i = i * 10) { - buffer.append("0"); - } - buffer.append(temp); - temp = dateHeader.get(Calendar.MONTH); - if (temp < 10) { - buffer.append("0"); - } - buffer.append(temp); - temp = dateHeader.get(Calendar.DAY_OF_MONTH); - if (temp < 10) { - buffer.append("0"); - } - buffer.append(temp); - buffer.append("T"); - temp = dateHeader.get(Calendar.HOUR_OF_DAY); - if (temp < 10) { - buffer.append("0"); - } - buffer.append(temp); - temp = dateHeader.get(Calendar.MINUTE); - if (temp < 10) { - buffer.append("0"); - } - buffer.append(temp); - temp = dateHeader.get(Calendar.SECOND); - if (temp < 10) { - buffer.append("0"); - } - buffer.append(temp); - - if (dateHeader.getTimeZone().getID().equals("UTC")) { - buffer.append("Z"); - } - - try { - value = buffer.toString().getBytes("ISO8859_1"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UnsupportedEncodingException: " + e.getMessage()); - } - - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(HeaderSet.TIME_ISO_8601); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.TIME_ISO_8601, null); - } - } - - // Time 4 Byte Header - dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE); - if (dateHeader != null) { - out.write(HeaderSet.TIME_4_BYTE); - - /* - * Need to call getTime() twice. The first call will return - * a java.util.Date object. The second call returns the number - * of milliseconds since January 1, 1970. We need to convert - * it to seconds since the TIME_4_BYTE expects the number of - * seconds since January 1, 1970. - */ - value = OBEXHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.TIME_4_BYTE, null); - } - } - - // Description Header - stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION); - if (stringHeader != null) { - out.write((byte)HeaderSet.DESCRIPTION); - value = OBEXHelper.convertToUnicodeByteArray(stringHeader); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.DESCRIPTION, null); - } - } - - // Target Header - value = (byte[])headImpl.getHeader(HeaderSet.TARGET); - if (value != null) { - out.write((byte)HeaderSet.TARGET); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.TARGET, null); - } - } - - // HTTP Header - value = (byte[])headImpl.getHeader(HeaderSet.HTTP); - if (value != null) { - out.write((byte)HeaderSet.HTTP); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.HTTP, null); - } - } - - // Who Header - value = (byte[])headImpl.getHeader(HeaderSet.WHO); - if (value != null) { - out.write((byte)HeaderSet.WHO); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.WHO, null); - } - } - - // Connection ID Header - value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER); - if (value != null) { - out.write((byte)HeaderSet.APPLICATION_PARAMETER); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null); - } - } - - // Object Class Header - value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS); - if (value != null) { - out.write((byte)HeaderSet.OBJECT_CLASS); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(HeaderSet.OBJECT_CLASS, null); - } - } - - // Check User Defined Headers - for (int i = 0; i < 16; i++) { - - //Unicode String Header - stringHeader = (String)headImpl.getHeader(i + 0x30); - if (stringHeader != null) { - out.write((byte)i + 0x30); - value = OBEXHelper.convertToUnicodeByteArray(stringHeader); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(i + 0x30, null); - } - } - - // Byte Sequence Header - value = (byte[])headImpl.getHeader(i + 0x70); - if (value != null) { - out.write((byte)i + 0x70); - length = value.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(value); - if (nullOut) { - headImpl.setHeader(i + 0x70, null); - } - } - - // Byte Header - byteHeader = (Byte)headImpl.getHeader(i + 0xB0); - if (byteHeader != null) { - out.write((byte)i + 0xB0); - out.write(byteHeader.byteValue()); - if (nullOut) { - headImpl.setHeader(i + 0xB0, null); - } - } - - // Integer header - intHeader = (Long)headImpl.getHeader(i + 0xF0); - if (intHeader != null) { - out.write((byte)i + 0xF0); - out.write(OBEXHelper.convertToByteArray(intHeader.longValue())); - if (nullOut) { - headImpl.setHeader(i + 0xF0, null); - } - } - } - - // Add the authentication challenge header - if (headImpl.authChall != null) { - out.write((byte)0x4D); - length = headImpl.authChall.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(headImpl.authChall); - if (nullOut) { - headImpl.authChall = null; - } - } - - // Add the authentication response header - if (headImpl.authResp != null) { - out.write((byte)0x4E); - length = headImpl.authResp.length + 3; - lengthArray[0] = (byte)(255 & (length >> 8)); - lengthArray[1] = (byte)(255 & length); - out.write(lengthArray); - out.write(headImpl.authResp); - if (nullOut) { - headImpl.authResp = null; - } - } - - } catch (IOException e) { - } finally { - result = out.toByteArray(); - try { - out.close(); - } catch (Exception ex) { - } - } - - return result; - - } - - /** - * Determines where the maximum divide is between headers. This method is - * used by put and get operations to separate headers to a size that meets - * the max packet size allowed. - * - * @param headerArray the headers to separate - * - * @param start the starting index to search - * - * @param maxSize the maximum size of a packet - * - * @return the index of the end of the header block to send or -1 if the - * header could not be divided because the header is too large - */ - public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) { - - int fullLength = 0; - int lastLength = -1; - int index = start; - int length = 0; - - while ((fullLength < maxSize) && (index < headerArray.length)) { - int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]); - lastLength = fullLength; - - switch (headerID & (0xC0)) { - - case 0x00: - // Fall through - case 0x40: - - index++; - length = (headerArray[index] < 0 ? headerArray[index] + 256 - : headerArray[index]); - length = length << 8; - index++; - length += (headerArray[index] < 0 ? headerArray[index] + 256 - : headerArray[index]); - length -= 3; - index++; - index += length; - fullLength += length + 3; - break; - - case 0x80: - - index++; - index++; - fullLength += 2; - break; - - case 0xC0: - - index += 5; - fullLength += 5; - break; - - } - - } - - /* - * Determine if this is the last header or not - */ - if (lastLength == 0) { - /* - * Since this is the last header, check to see if the size of this - * header is less then maxSize. If it is, return the length of the - * header, otherwise return -1. The length of the header is - * returned since it would be the start of the next header - */ - if (fullLength < maxSize) { - return headerArray.length; - } else { - return -1; - } - } else { - return lastLength + start; - } - } - - /** - * Converts the byte array to a long. - * - * @param b the byte array to convert to a long - * - * @return the byte array as a long - */ - public static long convertToLong(byte[] b) { - long result = 0; - long value = 0; - long power = 0; - - for (int i = (b.length - 1); i >= 0; i--) { - value = b[i]; - if (value < 0) { - value += 256; - } - - result = result | (value << power); - power += 8; - } - - return result; - } - - /** - * Converts the long to a 4 byte array. The long must be non negative. - * - * @param l the long to convert - * - * @return a byte array that is the same as the long - */ - public static byte[] convertToByteArray(long l) { - byte[] b = new byte[4]; - - b[0] = (byte)(255 & (l >> 24)); - b[1] = (byte)(255 & (l >> 16)); - b[2] = (byte)(255 & (l >> 8)); - b[3] = (byte)(255 & l); - - return b; - } - - /** - * Converts the String to a UNICODE byte array. It will also add the ending - * null characters to the end of the string. - * - * @param s the string to convert - * - * @return the unicode byte array of the string - */ - public static byte[] convertToUnicodeByteArray(String s) { - if (s == null) { - return null; - } - - char c[] = s.toCharArray(); - byte[] result = new byte[(c.length * 2) + 2]; - for (int i = 0; i < c.length; i++) { - result[(i * 2)] = (byte)(c[i] >> 8); - result[((i * 2) + 1)] = (byte)c[i]; - } - - // Add the UNICODE null character - result[result.length - 2] = 0; - result[result.length - 1] = 0; - - return result; - } - - /** - * Retrieves the value from the byte array for the tag value specified. The - * array should be of the form Tag - Length - Value triplet. - * - * @param tag the tag to retrieve from the byte array - * - * @param triplet the byte sequence containing the tag length value form - * - * @return the value of the specified tag - */ - public static byte[] getTagValue(byte tag, byte[] triplet) { - - int index = findTag(tag, triplet); - if (index == -1) { - return null; - } - - index++; - int length = triplet[index] & 0xFF; - - byte[] result = new byte[length]; - index++; - System.arraycopy(triplet, index, result, 0, length); - - return result; - } - - /** - * Finds the index that starts the tag value pair in the byte array provide. - * - * @param tag the tag to look for - * - * @param value the byte array to search - * - * @return the starting index of the tag or -1 if the tag could not be found - */ - public static int findTag(byte tag, byte[] value) { - int length = 0; - - if (value == null) { - return -1; - } - - int index = 0; - - while ((index < value.length) && (value[index] != tag)) { - length = value[index + 1] & 0xFF; - index += length + 2; - } - - if (index >= value.length) { - return -1; - } - - return index; - } - - /** - * Converts the byte array provided to a unicode string. - * - * @param b the byte array to convert to a string - * - * @param includesNull determine if the byte string provided contains the - * UNICODE null character at the end or not; if it does, it will be - * removed - * - * @return a Unicode string - * - * @param IllegalArgumentException if the byte array has an odd length - */ - public static String convertToUnicode(byte[] b, boolean includesNull) { - if (b == null) { - return null; - } - int arrayLength = b.length; - if (!((arrayLength % 2) == 0)) { - throw new IllegalArgumentException("Byte array not of a valid form"); - } - arrayLength = (arrayLength >> 1); - if (includesNull) { - arrayLength -= 1; - } - - char[] c = new char[arrayLength]; - for (int i = 0; i < arrayLength; i++) { - int upper = b[2 * i]; - int lower = b[(2 * i) + 1]; - if (upper < 0) { - upper += 256; - } - if (lower < 0) { - lower += 256; - } - - c[i] = (char)((upper << 8) | lower); - } - - return new String(c); - } - - /** - * Computes the MD5 hash algorithm on the byte array provided. This - * implementation of MD5 is optimized for OBEX in that it provides for a - * single entry and exist and thus does not build up the input before - * applying the hash. - * - * OPTIMIZATION: Embedd MD5 algorithm in this method. This will make the - * OPTIMIZATION: size smaller. - * - * @param in the byte array to hash - * - * @return the MD5 hash of the byte array - */ - public static byte[] computeMD5Hash(byte[] in) { - - MD5Hash hash = new MD5Hash(in); - return hash.computeDigest(); - } - - /** - * Computes an authentication challenge header. - * - * - * @param nonce the challenge that will be provided to the peer; the - * challenge must be 16 bytes long - * - * @param realm a short description that describes what password to use - * - * @param access if true then full access will be granted if - * successful; if false then read only access will be granted - * if successful - * - * @param userID if true, a user ID is required in the reply; - * if false, no user ID is required - * - * @exception IllegalArgumentException if the challenge is not 16 bytes - * long; if the realm can not be encoded in less then 255 bytes - * - * @exception IOException if the encoding scheme ISO 8859-1 is not supported - */ - public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access, - boolean userID) throws IOException { - byte[] authChall = null; - - if (nonce.length != 16) { - throw new IllegalArgumentException("Nonce must be 16 bytes long"); - } - - /* - * The authentication challenge is a byte sequence of the following form - * byte 0: 0x00 - the tag for the challenge - * byte 1: 0x10 - the length of the challenge; must be 16 - * byte 2-17: the authentication challenge - * byte 18: 0x01 - the options tag; this is optional in the spec, but - * we are going to include it in every message - * byte 19: 0x01 - length of the options; must be 1 - * byte 20: the value of the options; bit 0 is set if user ID is - * required; bit 1 is set if access mode is read only - * byte 21: 0x02 - the tag for authentication realm; only included if - * an authentication realm is specified - * byte 22: the length of the authentication realm; only included if - * the authentication realm is specified - * byte 23: the encoding scheme of the authentication realm; we will use - * the ISO 8859-1 encoding scheme since it is part of the KVM - * byte 24 & up: the realm if one is specified. - */ - if (realm == null) { - authChall = new byte[21]; - } else { - if (realm.length() >= 255) { - throw new IllegalArgumentException("Realm must be less then 255 bytes"); - } - authChall = new byte[24 + realm.length()]; - authChall[21] = 0x02; - authChall[22] = (byte)(realm.length() + 1); - authChall[23] = 0x01; // ISO 8859-1 Encoding - System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length()); - } - - // Include the nonce field in the header - authChall[0] = 0x00; - authChall[1] = 0x10; - System.arraycopy(nonce, 0, authChall, 2, 16); - - // Include the options header - authChall[18] = 0x01; - authChall[19] = 0x01; - authChall[20] = 0x00; - - if (!access) { - authChall[20] = (byte)(authChall[20] | 0x02); - } - if (userID) { - authChall[20] = (byte)(authChall[20] | 0x01); - } - - return authChall; - } -} - -/** - * This class will complete an MD5 hash of the buffer provided. - */ -class MD5Hash { - - // Constants for MD5Transform routine. - private static final int A1 = 7; - - private static final int A2 = 12; - - private static final int A3 = 17; - - private static final int A4 = 22; - - private static final int B1 = 5; - - private static final int B2 = 9; - - private static final int B3 = 14; - - private static final int B4 = 20; - - private static final int C1 = 4; - - private static final int C2 = 11; - - private static final int C3 = 16; - - private static final int C4 = 23; - - private static final int D1 = 6; - - private static final int D2 = 10; - - private static final int D3 = 15; - - private static final int D4 = 21; - - private int state[]; - - private int count[]; - - /** - * Keeps the present digest - */ - private byte buffer[]; - - /** - * Completes a hash on the data provided. - * - * @param data the byte array to hash - */ - public MD5Hash(byte data[]) { - buffer = new byte[64]; - state = new int[4]; - count = new int[2]; - - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; - - count[0] = 0; - count[1] = 0; - - MD5Update(data, 0, data.length); - } - - /** - * Updates the MD5 hash buffer. - * - * @param input byte array of data - * - * @param offset offset into the array to start the digest calculation - * - * @param inputLen the length of the byte array - */ - private void MD5Update(byte input[], int offset, int inputLen) { - int i, index, partLen; - - // Compute number of bytes mod 64 - index = (count[0] >>> 3) & 0x3F; - - // Update number of bits - int slen = inputLen << 3; - if ((count[0] += slen) < slen) { - count[1]++; - } - - count[1] += (inputLen >>> 29); - - partLen = 64 - index; - // Transform as many times as possible. - if (inputLen >= partLen) { - copy(index, input, offset, partLen); - - MD5Transform(buffer, 0, 0); - - for (i = partLen; i + 63 < inputLen; i += 64) { - MD5Transform(input, offset, i); - } - - index = 0; - } else { - i = 0; - } - - copy(index, input, i + offset, inputLen - i); - } - - /** - * Computes the final MD5 digest - * - * @return the MD5 digest - */ - public byte[] computeDigest() { - byte bits[]; - byte digest[]; - int index; - int length; - - // Save number of bits - bits = MD5Encode(count, 8); - - // Pad out to 56 mod 64. - index = ((count[0] >>> 3) & 0x3f); - length = (index < 56) ? (56 - index) : (120 - index); - - // build padding buffer. - if (length > 0) { - byte padding[] = new byte[length]; - padding[0] = (byte)0x80; - for (int i = 1; i < length; i++) { - padding[i] = 0; - } - - MD5Update(padding, 0, length); - } - - // Append length - MD5Update(bits, 0, 8); - - // Store state in digest - digest = MD5Encode(state, 16); - - return digest; - } - - /** - * Copies the input array into the local objects buffer. It performs a - * check to verify that data is available to copy. - * - * @param startIndex the offset into the local buffer to copy - * - * @param input the array to copy into the local buffer - * - * @param index the index to start copying from - * - * @param length the amount of data to copy - */ - private void copy(int startIndex, byte input[], int index, int length) { - if (index == input.length) - return; - System.arraycopy(input, index, buffer, startIndex, length); - } - - /** - * Rotates the bytes in x n times to the left. - * The rotation wraps the bits around. - * - * @param x the integer to rotate - * - * @param n the number of bits to rotate - * - * @return x rotated to the left n times - */ - private int rotate(int x, int n) { - return (((x) << (n)) | ((x) >>> (32 - (n)))); - } - - /** - * Completes a single step in the MD5 hash algorithm. - */ - private int MD5Step(int a, int b, int c, int d, int x, int s, int ac, int round) { - switch (round) { - case 1: - a += (((b) & (c)) | ((~b) & (d))) + (x) + (ac); - break; - case 2: - a += (((b) & (d)) | ((c) & (~d))) + (x) + (ac); - break; - case 3: - a += ((b) ^ (c) ^ (d)) + (x) + (ac); - break; - case 4: - a += ((c) ^ ((b) | (~d))) + (x) + (ac); - break; - } - a = rotate(a, (s)); - a += (b); - return a; - } - - /** - * Performs the core MD5 algorithm. This method will add the data provided - * and recompute the hash. - * - * @param data the block of data to add - * - * @param index the starting index into the data to start processing - * - * @param length the length of the byte array to process - */ - private void MD5Transform(byte data[], int index, int length) { - int a = state[0]; - int b = state[1]; - int c = state[2]; - int d = state[3]; - int x[]; - - x = MD5Decode(data, index, length, 64); - - // Round 1 - a = MD5Step(a, b, c, d, x[0], A1, 0xd76aa478, 1); - d = MD5Step(d, a, b, c, x[1], A2, 0xe8c7b756, 1); - c = MD5Step(c, d, a, b, x[2], A3, 0x242070db, 1); - b = MD5Step(b, c, d, a, x[3], A4, 0xc1bdceee, 1); - a = MD5Step(a, b, c, d, x[4], A1, 0xf57c0faf, 1); - d = MD5Step(d, a, b, c, x[5], A2, 0x4787c62a, 1); - c = MD5Step(c, d, a, b, x[6], A3, 0xa8304613, 1); - b = MD5Step(b, c, d, a, x[7], A4, 0xfd469501, 1); - a = MD5Step(a, b, c, d, x[8], A1, 0x698098d8, 1); - d = MD5Step(d, a, b, c, x[9], A2, 0x8b44f7af, 1); - c = MD5Step(c, d, a, b, x[10], A3, 0xffff5bb1, 1); - b = MD5Step(b, c, d, a, x[11], A4, 0x895cd7be, 1); - a = MD5Step(a, b, c, d, x[12], A1, 0x6b901122, 1); - d = MD5Step(d, a, b, c, x[13], A2, 0xfd987193, 1); - c = MD5Step(c, d, a, b, x[14], A3, 0xa679438e, 1); - b = MD5Step(b, c, d, a, x[15], A4, 0x49b40821, 1); - - // Round 2 - a = MD5Step(a, b, c, d, x[1], B1, 0xf61e2562, 2); - d = MD5Step(d, a, b, c, x[6], B2, 0xc040b340, 2); - c = MD5Step(c, d, a, b, x[11], B3, 0x265e5a51, 2); - b = MD5Step(b, c, d, a, x[0], B4, 0xe9b6c7aa, 2); - a = MD5Step(a, b, c, d, x[5], B1, 0xd62f105d, 2); - d = MD5Step(d, a, b, c, x[10], B2, 0x2441453, 2); - c = MD5Step(c, d, a, b, x[15], B3, 0xd8a1e681, 2); - b = MD5Step(b, c, d, a, x[4], B4, 0xe7d3fbc8, 2); - a = MD5Step(a, b, c, d, x[9], B1, 0x21e1cde6, 2); - d = MD5Step(d, a, b, c, x[14], B2, 0xc33707d6, 2); - c = MD5Step(c, d, a, b, x[3], B3, 0xf4d50d87, 2); - b = MD5Step(b, c, d, a, x[8], B4, 0x455a14ed, 2); - a = MD5Step(a, b, c, d, x[13], B1, 0xa9e3e905, 2); - d = MD5Step(d, a, b, c, x[2], B2, 0xfcefa3f8, 2); - c = MD5Step(c, d, a, b, x[7], B3, 0x676f02d9, 2); - b = MD5Step(b, c, d, a, x[12], B4, 0x8d2a4c8a, 2); - - // Round 3 - a = MD5Step(a, b, c, d, x[5], C1, 0xfffa3942, 3); - d = MD5Step(d, a, b, c, x[8], C2, 0x8771f681, 3); - c = MD5Step(c, d, a, b, x[11], C3, 0x6d9d6122, 3); - b = MD5Step(b, c, d, a, x[14], C4, 0xfde5380c, 3); - a = MD5Step(a, b, c, d, x[1], C1, 0xa4beea44, 3); - d = MD5Step(d, a, b, c, x[4], C2, 0x4bdecfa9, 3); - c = MD5Step(c, d, a, b, x[7], C3, 0xf6bb4b60, 3); - b = MD5Step(b, c, d, a, x[10], C4, 0xbebfbc70, 3); - a = MD5Step(a, b, c, d, x[13], C1, 0x289b7ec6, 3); - d = MD5Step(d, a, b, c, x[0], C2, 0xeaa127fa, 3); - c = MD5Step(c, d, a, b, x[3], C3, 0xd4ef3085, 3); - b = MD5Step(b, c, d, a, x[6], C4, 0x4881d05, 3); - a = MD5Step(a, b, c, d, x[9], C1, 0xd9d4d039, 3); - d = MD5Step(d, a, b, c, x[12], C2, 0xe6db99e5, 3); - c = MD5Step(c, d, a, b, x[15], C3, 0x1fa27cf8, 3); - b = MD5Step(b, c, d, a, x[2], C4, 0xc4ac5665, 3); - - // Round 4 - a = MD5Step(a, b, c, d, x[0], D1, 0xf4292244, 4); - d = MD5Step(d, a, b, c, x[7], D2, 0x432aff97, 4); - c = MD5Step(c, d, a, b, x[14], D3, 0xab9423a7, 4); - b = MD5Step(b, c, d, a, x[5], D4, 0xfc93a039, 4); - a = MD5Step(a, b, c, d, x[12], D1, 0x655b59c3, 4); - d = MD5Step(d, a, b, c, x[3], D2, 0x8f0ccc92, 4); - c = MD5Step(c, d, a, b, x[10], D3, 0xffeff47d, 4); - b = MD5Step(b, c, d, a, x[1], D4, 0x85845dd1, 4); - a = MD5Step(a, b, c, d, x[8], D1, 0x6fa87e4f, 4); - d = MD5Step(d, a, b, c, x[15], D2, 0xfe2ce6e0, 4); - c = MD5Step(c, d, a, b, x[6], D3, 0xa3014314, 4); - b = MD5Step(b, c, d, a, x[13], D4, 0x4e0811a1, 4); - a = MD5Step(a, b, c, d, x[4], D1, 0xf7537e82, 4); - d = MD5Step(d, a, b, c, x[11], D2, 0xbd3af235, 4); - c = MD5Step(c, d, a, b, x[2], D3, 0x2ad7d2bb, 4); - b = MD5Step(b, c, d, a, x[9], D4, 0xeb86d391, 4); - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - } - - /** - * Encodes the input array. input must be a multiple of - * four. - * - * @param input the array to encode - * - * @param length the length of the array to encode - */ - private byte[] MD5Encode(int input[], int length) { - int i, j; - byte output[] = new byte[length]; - - for (i = 0, j = 0; j < length; i++, j += 4) { - output[j] = (byte)(input[i] & 0xff); - output[j + 1] = (byte)((input[i] >>> 8) & 0xff); - output[j + 2] = (byte)((input[i] >>> 16) & 0xff); - output[j + 3] = (byte)((input[i] >>> 24) & 0xff); - } - - return output; - } - - /** - * Decodes the array. The input array must be a multiple of - * four. Results are undefined if this is not true. - * - * @param input the array to decode - * - * @param index the starting position into the input array to start decoding - * - * @param posn - * - * @param length - */ - private int[] MD5Decode(byte input[], int offset, int posn, int length) { - int output[] = new int[length / 4]; - int i, j; - int limit = length + posn + offset; - - for (i = 0, j = offset + posn; j < limit; i++, j += 4) - output[i] = ((input[j]) & 0xff) | (((input[j + 1]) & 0xff) << 8) - | (((input[j + 2]) & 0xff) << 16) | (((input[j + 3]) & 0xff) << 24); - - return output; - } -} diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java new file mode 100644 index 0000000..5f1c493 --- /dev/null +++ b/obex/javax/obex/ObexHelper.java @@ -0,0 +1,995 @@ +/* + * Copyright (c) 2008-2009, Motorola, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * - Neither the name of the Motorola, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package javax.obex; + +import android.security.Md5MessageDigest; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +/** + * This class defines a set of helper methods for the implementation of Obex. + * + * @hide + */ +public final class ObexHelper { + + /** Prevent object construction of helper class */ + private ObexHelper() {} + + /** + * Defines the OBEX CONTINUE response code. + *

+ * The value of OBEX_HTTP_CONTINUE is 0x90 (144). + */ + public static final int OBEX_HTTP_CONTINUE = 0x90; + + /** + * The maximum packet size for OBEX packets that this client can handle. + * At present, this must be changed for each port. + * + * OPTIMIZATION: The max packet size should be the Max incoming MTU minus + * OPTIMIZATION: L2CAP package headers and RFCOMM package headers. + * + * OPTIMIZATION: Retrieve the max incoming MTU from + * OPTIMIZATION: LocalDevice.getProperty(). + */ + /** android note + * set as 0xFFFE to match remote MPS + */ + public static final int MAX_PACKET_SIZE_INT = 0xFFFE; + + /** + * Updates the HeaderSet with the headers received in the byte array + * provided. Invalid headers are ignored. + *

+ * The first two bits of an OBEX Header specifies the type of object that + * is being sent. The table below specifies the meaning of the high + * bits. + * + * + * + * + * + * + *
Bits 8 and 7ValueDescription
000x00Null Terminated Unicode text, prefixed + * with 2 byte unsigned integer
010x40Byte Sequence, length prefixed with + * 2 byte unsigned integer
100x801 byte quantity
110xC04 byte quantity - transmitted in + * network byte order (high byte first
+ * This method uses the information in this table to determine the type of + * Java object to create and passes that object with the full header + * to setHeader() to update the HeaderSet object. Invalid headers will + * cause an exception to be thrown. When it is thrown, it is ignored. + * + * @param header the HeaderSet to update + * + * @param headerArray the byte array containing headers + * + * @return the result of the last start body or end body header provided; + * the first byte in the result will specify if a body or end of body is + * received + * + * @throws IOException if an invalid header was found + */ + public static byte[] updateHeaderSet(HeaderSet header, byte[] headerArray) throws IOException { + int index = 0; + int length = 0; + int headerID; + byte[] value = null; + byte[] body = null; + HeaderSet headerImpl = header; + try { + while (index < headerArray.length) { + headerID = 0xFF & headerArray[index]; + switch (headerID & (0xC0)) { + + /* + * 0x00 is a unicode null terminate string with the first + * two bytes after the header identifier being the length + */ + case 0x00: + // Fall through + /* + * 0x40 is a byte sequence with the first + * two bytes after the header identifier being the length + */ + case 0x40: + boolean trimTail = true; + index++; + length = 0xFF & headerArray[index]; + length = length << 8; + index++; + length += 0xFF & headerArray[index]; + length -= 3; + index++; + value = new byte[length]; + System.arraycopy(headerArray, index, value, 0, length); + if (length == 0 || (length > 0 && (value[length - 1] != 0))) { + trimTail = false; + } + switch (headerID) { + case HeaderSet.TYPE: + try { + // Remove trailing null + if (trimTail == false) { + headerImpl.setHeader(headerID, new String(value, 0, + value.length, "ISO8859_1")); + } else { + headerImpl.setHeader(headerID, new String(value, 0, + value.length - 1, "ISO8859_1")); + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("ISO8859_1 is not supported" + + e.getMessage()); + } + break; + + // This is the constant for the authentication challenge header + // This header does not have a constant defined in the Java + // OBEX API + case 0x4D: + headerImpl.authChall = new byte[length]; + System.arraycopy(headerArray, index, headerImpl.authChall, 0, + length); + break; + + // This is the constant for the authentication response header + // This header does not have a constant defined in the Java + // OBEX API + case 0x4E: + headerImpl.authResp = new byte[length]; + System + .arraycopy(headerArray, index, headerImpl.authResp, 0, + length); + break; + + /* + * These two case statements are for the body (0x48) + * and end of body (0x49) headers. + */ + case 0x48: + /* Fall Through */ + case 0x49: + body = new byte[length + 1]; + body[0] = (byte)headerID; + System.arraycopy(headerArray, index, body, 1, length); + break; + + case HeaderSet.TIME_ISO_8601: + try { + String dateString = new String(value, "ISO8859_1"); + Calendar temp = Calendar.getInstance(); + if ((dateString.length() == 16) + && (dateString.charAt(15) == 'Z')) { + temp.setTimeZone(TimeZone.getTimeZone("UTC")); + } + temp.set(Calendar.YEAR, Integer.parseInt(dateString.substring( + 0, 4))); + temp.set(Calendar.MONTH, Integer.parseInt(dateString.substring( + 4, 6))); + temp.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateString + .substring(6, 8))); + temp.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dateString + .substring(9, 11))); + temp.set(Calendar.MINUTE, Integer.parseInt(dateString + .substring(11, 13))); + temp.set(Calendar.SECOND, Integer.parseInt(dateString + .substring(13, 15))); + headerImpl.setHeader(HeaderSet.TIME_ISO_8601, temp); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("ISO8859_1 is not supported" + + e.getMessage()); + } catch (Exception e) { + throw new IOException( + "Time Header does not follow ISO 8601 standard"); + } + break; + + default: + try { + if ((headerID & 0xC0) == 0x00) { + headerImpl.setHeader(headerID, ObexHelper.convertToUnicode( + value, true)); + } else { + headerImpl.setHeader(headerID, value); + } + } catch (Exception e) { + // Not a valid header so ignore + } + } + + index += length; + break; + + /* + * 0x80 is a byte header. The only valid byte headers are + * the 16 user defined byte headers. + */ + case 0x80: + index++; + try { + headerImpl.setHeader(headerID, Byte.valueOf(headerArray[index])); + } catch (Exception e) { + // Not a valid header so ignore + } + index++; + break; + + /* + * 0xC0 is a 4 byte unsigned integer header and with the + * exception of TIME_4_BYTE will be converted to a Long + * and added. + */ + case 0xC0: + index++; + value = new byte[4]; + System.arraycopy(headerArray, index, value, 0, 4); + try { + if (headerID != HeaderSet.TIME_4_BYTE) { + // Determine if it is a connection ID. These + // need to be handled differently + if (headerID == 0xCB) { + headerImpl.connectionID = new byte[4]; + System.arraycopy(value, 0, headerImpl.connectionID, 0, 4); + } else { + headerImpl.setHeader(headerID, Long + .valueOf(convertToLong(value))); + } + } else { + Calendar temp = Calendar.getInstance(); + temp.setTime(new Date(convertToLong(value) * 1000L)); + headerImpl.setHeader(HeaderSet.TIME_4_BYTE, temp); + } + } catch (Exception e) { + // Not a valid header so ignore + throw new IOException("Header was not formatted properly"); + } + index += 4; + break; + } + + } + } catch (IOException e) { + throw new IOException("Header was not formatted properly"); + } + + return body; + } + + /** + * Creates the header part of OBEX packet based on the header provided. + * + * OPTIMIZATION: Could use getHeaderList() to get the array of headers to + * OPTIMIZATION: include and then use the high two bits to determine the + * OPTIMIZATION: the type of the object and construct the byte array from + * OPTIMIZATION: that. This will make the size smaller. + * + * @param head the header used to construct the byte array + * + * @param nullOut true if the header should be set to + * null once it is added to the array or false + * if it should not be nulled out + * + * @return the header of an OBEX packet + */ + public static byte[] createHeader(HeaderSet head, boolean nullOut) { + Long intHeader = null; + String stringHeader = null; + Calendar dateHeader = null; + Byte byteHeader = null; + StringBuffer buffer = null; + byte[] value = null; + byte[] result = null; + byte[] lengthArray = new byte[2]; + int length; + HeaderSet headImpl = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (!(head instanceof HeaderSet)) { + throw new IllegalArgumentException("Header not created by createHeaderSet"); + } + headImpl = head; + + try { + /* + * Determine if there is a connection ID to send. If there is, + * then it should be the first header in the packet. + */ + if ((headImpl.connectionID != null) && (headImpl.getHeader(HeaderSet.TARGET) == null)) { + + out.write((byte)0xCB); + out.write(headImpl.connectionID); + } + + // Count Header + intHeader = (Long)headImpl.getHeader(HeaderSet.COUNT); + if (intHeader != null) { + out.write((byte)HeaderSet.COUNT); + value = ObexHelper.convertToByteArray(intHeader.longValue()); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.COUNT, null); + } + } + + // Name Header + stringHeader = (String)headImpl.getHeader(HeaderSet.NAME); + if (stringHeader != null) { + out.write((byte)HeaderSet.NAME); + value = ObexHelper.convertToUnicodeByteArray(stringHeader); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.NAME, null); + } + } + + // Type Header + stringHeader = (String)headImpl.getHeader(HeaderSet.TYPE); + if (stringHeader != null) { + out.write((byte)HeaderSet.TYPE); + try { + value = stringHeader.getBytes("ISO8859_1"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Unsupported Encoding Scheme: " + e.getMessage()); + } + + length = value.length + 4; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + out.write(0x00); + if (nullOut) { + headImpl.setHeader(HeaderSet.TYPE, null); + } + } + + // Length Header + intHeader = (Long)headImpl.getHeader(HeaderSet.LENGTH); + if (intHeader != null) { + out.write((byte)HeaderSet.LENGTH); + value = ObexHelper.convertToByteArray(intHeader.longValue()); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.LENGTH, null); + } + } + + // Time ISO Header + dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_ISO_8601); + if (dateHeader != null) { + + /* + * The ISO Header should take the form YYYYMMDDTHHMMSSZ. The + * 'Z' will only be included if it is a UTC time. + */ + buffer = new StringBuffer(); + int temp = dateHeader.get(Calendar.YEAR); + for (int i = temp; i < 1000; i = i * 10) { + buffer.append("0"); + } + buffer.append(temp); + temp = dateHeader.get(Calendar.MONTH); + if (temp < 10) { + buffer.append("0"); + } + buffer.append(temp); + temp = dateHeader.get(Calendar.DAY_OF_MONTH); + if (temp < 10) { + buffer.append("0"); + } + buffer.append(temp); + buffer.append("T"); + temp = dateHeader.get(Calendar.HOUR_OF_DAY); + if (temp < 10) { + buffer.append("0"); + } + buffer.append(temp); + temp = dateHeader.get(Calendar.MINUTE); + if (temp < 10) { + buffer.append("0"); + } + buffer.append(temp); + temp = dateHeader.get(Calendar.SECOND); + if (temp < 10) { + buffer.append("0"); + } + buffer.append(temp); + + if (dateHeader.getTimeZone().getID().equals("UTC")) { + buffer.append("Z"); + } + + try { + value = buffer.toString().getBytes("ISO8859_1"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UnsupportedEncodingException: " + e.getMessage()); + } + + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(HeaderSet.TIME_ISO_8601); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.TIME_ISO_8601, null); + } + } + + // Time 4 Byte Header + dateHeader = (Calendar)headImpl.getHeader(HeaderSet.TIME_4_BYTE); + if (dateHeader != null) { + out.write(HeaderSet.TIME_4_BYTE); + + /* + * Need to call getTime() twice. The first call will return + * a java.util.Date object. The second call returns the number + * of milliseconds since January 1, 1970. We need to convert + * it to seconds since the TIME_4_BYTE expects the number of + * seconds since January 1, 1970. + */ + value = ObexHelper.convertToByteArray(dateHeader.getTime().getTime() / 1000L); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.TIME_4_BYTE, null); + } + } + + // Description Header + stringHeader = (String)headImpl.getHeader(HeaderSet.DESCRIPTION); + if (stringHeader != null) { + out.write((byte)HeaderSet.DESCRIPTION); + value = ObexHelper.convertToUnicodeByteArray(stringHeader); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.DESCRIPTION, null); + } + } + + // Target Header + value = (byte[])headImpl.getHeader(HeaderSet.TARGET); + if (value != null) { + out.write((byte)HeaderSet.TARGET); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.TARGET, null); + } + } + + // HTTP Header + value = (byte[])headImpl.getHeader(HeaderSet.HTTP); + if (value != null) { + out.write((byte)HeaderSet.HTTP); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.HTTP, null); + } + } + + // Who Header + value = (byte[])headImpl.getHeader(HeaderSet.WHO); + if (value != null) { + out.write((byte)HeaderSet.WHO); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.WHO, null); + } + } + + // Connection ID Header + value = (byte[])headImpl.getHeader(HeaderSet.APPLICATION_PARAMETER); + if (value != null) { + out.write((byte)HeaderSet.APPLICATION_PARAMETER); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.APPLICATION_PARAMETER, null); + } + } + + // Object Class Header + value = (byte[])headImpl.getHeader(HeaderSet.OBJECT_CLASS); + if (value != null) { + out.write((byte)HeaderSet.OBJECT_CLASS); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(HeaderSet.OBJECT_CLASS, null); + } + } + + // Check User Defined Headers + for (int i = 0; i < 16; i++) { + + //Unicode String Header + stringHeader = (String)headImpl.getHeader(i + 0x30); + if (stringHeader != null) { + out.write((byte)i + 0x30); + value = ObexHelper.convertToUnicodeByteArray(stringHeader); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(i + 0x30, null); + } + } + + // Byte Sequence Header + value = (byte[])headImpl.getHeader(i + 0x70); + if (value != null) { + out.write((byte)i + 0x70); + length = value.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(value); + if (nullOut) { + headImpl.setHeader(i + 0x70, null); + } + } + + // Byte Header + byteHeader = (Byte)headImpl.getHeader(i + 0xB0); + if (byteHeader != null) { + out.write((byte)i + 0xB0); + out.write(byteHeader.byteValue()); + if (nullOut) { + headImpl.setHeader(i + 0xB0, null); + } + } + + // Integer header + intHeader = (Long)headImpl.getHeader(i + 0xF0); + if (intHeader != null) { + out.write((byte)i + 0xF0); + out.write(ObexHelper.convertToByteArray(intHeader.longValue())); + if (nullOut) { + headImpl.setHeader(i + 0xF0, null); + } + } + } + + // Add the authentication challenge header + if (headImpl.authChall != null) { + out.write((byte)0x4D); + length = headImpl.authChall.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(headImpl.authChall); + if (nullOut) { + headImpl.authChall = null; + } + } + + // Add the authentication response header + if (headImpl.authResp != null) { + out.write((byte)0x4E); + length = headImpl.authResp.length + 3; + lengthArray[0] = (byte)(255 & (length >> 8)); + lengthArray[1] = (byte)(255 & length); + out.write(lengthArray); + out.write(headImpl.authResp); + if (nullOut) { + headImpl.authResp = null; + } + } + + } catch (IOException e) { + } finally { + result = out.toByteArray(); + try { + out.close(); + } catch (Exception ex) { + } + } + + return result; + + } + + /** + * Determines where the maximum divide is between headers. This method is + * used by put and get operations to separate headers to a size that meets + * the max packet size allowed. + * + * @param headerArray the headers to separate + * + * @param start the starting index to search + * + * @param maxSize the maximum size of a packet + * + * @return the index of the end of the header block to send or -1 if the + * header could not be divided because the header is too large + */ + public static int findHeaderEnd(byte[] headerArray, int start, int maxSize) { + + int fullLength = 0; + int lastLength = -1; + int index = start; + int length = 0; + + while ((fullLength < maxSize) && (index < headerArray.length)) { + int headerID = (headerArray[index] < 0 ? headerArray[index] + 256 : headerArray[index]); + lastLength = fullLength; + + switch (headerID & (0xC0)) { + + case 0x00: + // Fall through + case 0x40: + + index++; + length = (headerArray[index] < 0 ? headerArray[index] + 256 + : headerArray[index]); + length = length << 8; + index++; + length += (headerArray[index] < 0 ? headerArray[index] + 256 + : headerArray[index]); + length -= 3; + index++; + index += length; + fullLength += length + 3; + break; + + case 0x80: + + index++; + index++; + fullLength += 2; + break; + + case 0xC0: + + index += 5; + fullLength += 5; + break; + + } + + } + + /* + * Determine if this is the last header or not + */ + if (lastLength == 0) { + /* + * Since this is the last header, check to see if the size of this + * header is less then maxSize. If it is, return the length of the + * header, otherwise return -1. The length of the header is + * returned since it would be the start of the next header + */ + if (fullLength < maxSize) { + return headerArray.length; + } else { + return -1; + } + } else { + return lastLength + start; + } + } + + /** + * Converts the byte array to a long. + * + * @param b the byte array to convert to a long + * + * @return the byte array as a long + */ + public static long convertToLong(byte[] b) { + long result = 0; + long value = 0; + long power = 0; + + for (int i = (b.length - 1); i >= 0; i--) { + value = b[i]; + if (value < 0) { + value += 256; + } + + result = result | (value << power); + power += 8; + } + + return result; + } + + /** + * Converts the long to a 4 byte array. The long must be non negative. + * + * @param l the long to convert + * + * @return a byte array that is the same as the long + */ + public static byte[] convertToByteArray(long l) { + byte[] b = new byte[4]; + + b[0] = (byte)(255 & (l >> 24)); + b[1] = (byte)(255 & (l >> 16)); + b[2] = (byte)(255 & (l >> 8)); + b[3] = (byte)(255 & l); + + return b; + } + + /** + * Converts the String to a UNICODE byte array. It will also add the ending + * null characters to the end of the string. + * + * @param s the string to convert + * + * @return the unicode byte array of the string + */ + public static byte[] convertToUnicodeByteArray(String s) { + if (s == null) { + return null; + } + + char c[] = s.toCharArray(); + byte[] result = new byte[(c.length * 2) + 2]; + for (int i = 0; i < c.length; i++) { + result[(i * 2)] = (byte)(c[i] >> 8); + result[((i * 2) + 1)] = (byte)c[i]; + } + + // Add the UNICODE null character + result[result.length - 2] = 0; + result[result.length - 1] = 0; + + return result; + } + + /** + * Retrieves the value from the byte array for the tag value specified. The + * array should be of the form Tag - Length - Value triplet. + * + * @param tag the tag to retrieve from the byte array + * + * @param triplet the byte sequence containing the tag length value form + * + * @return the value of the specified tag + */ + public static byte[] getTagValue(byte tag, byte[] triplet) { + + int index = findTag(tag, triplet); + if (index == -1) { + return null; + } + + index++; + int length = triplet[index] & 0xFF; + + byte[] result = new byte[length]; + index++; + System.arraycopy(triplet, index, result, 0, length); + + return result; + } + + /** + * Finds the index that starts the tag value pair in the byte array provide. + * + * @param tag the tag to look for + * + * @param value the byte array to search + * + * @return the starting index of the tag or -1 if the tag could not be found + */ + public static int findTag(byte tag, byte[] value) { + int length = 0; + + if (value == null) { + return -1; + } + + int index = 0; + + while ((index < value.length) && (value[index] != tag)) { + length = value[index + 1] & 0xFF; + index += length + 2; + } + + if (index >= value.length) { + return -1; + } + + return index; + } + + /** + * Converts the byte array provided to a unicode string. + * + * @param b the byte array to convert to a string + * + * @param includesNull determine if the byte string provided contains the + * UNICODE null character at the end or not; if it does, it will be + * removed + * + * @return a Unicode string + * + * @param IllegalArgumentException if the byte array has an odd length + */ + public static String convertToUnicode(byte[] b, boolean includesNull) { + if (b == null) { + return null; + } + int arrayLength = b.length; + if (!((arrayLength % 2) == 0)) { + throw new IllegalArgumentException("Byte array not of a valid form"); + } + arrayLength = (arrayLength >> 1); + if (includesNull) { + arrayLength -= 1; + } + + char[] c = new char[arrayLength]; + for (int i = 0; i < arrayLength; i++) { + int upper = b[2 * i]; + int lower = b[(2 * i) + 1]; + if (upper < 0) { + upper += 256; + } + if (lower < 0) { + lower += 256; + } + + c[i] = (char)((upper << 8) | lower); + } + + return new String(c); + } + + /** + * Compute the MD5 hash of the byte array provided. + * Does not accumulate input. + * + * @param in the byte array to hash + * @return the MD5 hash of the byte array + */ + public static byte[] computeMd5Hash(byte[] in) { + Md5MessageDigest md5 = new Md5MessageDigest(); + return md5.digest(in); + } + + /** + * Computes an authentication challenge header. + * + * + * @param nonce the challenge that will be provided to the peer; the + * challenge must be 16 bytes long + * + * @param realm a short description that describes what password to use + * + * @param access if true then full access will be granted if + * successful; if false then read only access will be granted + * if successful + * + * @param userID if true, a user ID is required in the reply; + * if false, no user ID is required + * + * @throws IllegalArgumentException if the challenge is not 16 bytes + * long; if the realm can not be encoded in less then 255 bytes + * + * @throws IOException if the encoding scheme ISO 8859-1 is not supported + */ + public static byte[] computeAuthenticationChallenge(byte[] nonce, String realm, boolean access, + boolean userID) throws IOException { + byte[] authChall = null; + + if (nonce.length != 16) { + throw new IllegalArgumentException("Nonce must be 16 bytes long"); + } + + /* + * The authentication challenge is a byte sequence of the following form + * byte 0: 0x00 - the tag for the challenge + * byte 1: 0x10 - the length of the challenge; must be 16 + * byte 2-17: the authentication challenge + * byte 18: 0x01 - the options tag; this is optional in the spec, but + * we are going to include it in every message + * byte 19: 0x01 - length of the options; must be 1 + * byte 20: the value of the options; bit 0 is set if user ID is + * required; bit 1 is set if access mode is read only + * byte 21: 0x02 - the tag for authentication realm; only included if + * an authentication realm is specified + * byte 22: the length of the authentication realm; only included if + * the authentication realm is specified + * byte 23: the encoding scheme of the authentication realm; we will use + * the ISO 8859-1 encoding scheme since it is part of the KVM + * byte 24 & up: the realm if one is specified. + */ + if (realm == null) { + authChall = new byte[21]; + } else { + if (realm.length() >= 255) { + throw new IllegalArgumentException("Realm must be less then 255 bytes"); + } + authChall = new byte[24 + realm.length()]; + authChall[21] = 0x02; + authChall[22] = (byte)(realm.length() + 1); + authChall[23] = 0x01; // ISO 8859-1 Encoding + System.arraycopy(realm.getBytes("ISO8859_1"), 0, authChall, 24, realm.length()); + } + + // Include the nonce field in the header + authChall[0] = 0x00; + authChall[1] = 0x10; + System.arraycopy(nonce, 0, authChall, 2, 16); + + // Include the options header + authChall[18] = 0x01; + authChall[19] = 0x01; + authChall[20] = 0x00; + + if (!access) { + authChall[20] = (byte)(authChall[20] | 0x02); + } + if (userID) { + authChall[20] = (byte)(authChall[20] | 0x01); + } + + return authChall; + } +} diff --git a/obex/javax/obex/ObexSession.java b/obex/javax/obex/ObexSession.java index b3da89c..1dc50c6 100644 --- a/obex/javax/obex/ObexSession.java +++ b/obex/javax/obex/ObexSession.java @@ -45,19 +45,10 @@ import java.io.IOException; * This interface serves as the common super class for * ClientSession and ServerSession. * - * @version 0.3 November 28, 2008 + * @hide */ public interface ObexSession { - /* - public InputStream openInputStream() throws IOException; - - public DataInputStream openDataInputStream() throws IOException; - - public OutputStream openOutputStream() throws IOException; - - public DataOutputStream openDataOutputStream() throws IOException;*/ - public void close() throws IOException; } diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java index b1734ff..d0ba0c9 100644 --- a/obex/javax/obex/ObexTransport.java +++ b/obex/javax/obex/ObexTransport.java @@ -52,7 +52,7 @@ import java.io.OutputStream; * RFCOMM device file medium may be constructed from a file descriptor or simply * a string while the TCP medium usually from a socket. * - * @version 0.3 November 28, 2008 + * @hide */ public interface ObexTransport { @@ -73,6 +73,5 @@ public interface ObexTransport { DataInputStream openDataInputStream() throws IOException; DataOutputStream openDataOutputStream() throws IOException; - //ObexSession accept() throws IOException; } diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java index 120852a..5a8bcec 100644 --- a/obex/javax/obex/Operation.java +++ b/obex/javax/obex/Operation.java @@ -124,7 +124,7 @@ import java.io.OutputStream; * getResponseCode() will cause an implicit close on the * InputStream. No further data may be read at this point. * - * @version 0.3 November 28, 2008 + * @hide */ public interface Operation { @@ -134,7 +134,7 @@ public interface Operation { * object. No headers are sent in the abort request. This will end the * operation since close() will be called by this method. * - * @exception IOException if the transaction has already ended or if an + * @throws IOException if the transaction has already ended or if an * OBEX server calls this method */ public void abort() throws IOException; @@ -146,7 +146,7 @@ public interface Operation { * * @return the headers received during this Operation * - * @exception IOException if this Operation has been closed + * @throws IOException if this Operation has been closed */ public HeaderSet getReceivedHeaders() throws IOException; @@ -156,14 +156,14 @@ public interface Operation { * * @param headers the headers to send in the next message * - * @exception IOException if this Operation has been closed + * @throws IOException if this Operation has been closed * or the transaction has ended and no further messages will be exchanged * - * @exception IllegalArgumentException if headers was not created + * @throws IllegalArgumentException if headers was not created * by a call to ServerRequestHandler.createHeaderSet() or * ClientSession.createHeaderSet() * - * @exception NullPointerException if headers if null + * @throws NullPointerException if headers if null */ public void sendHeaders(HeaderSet headers) throws IOException; @@ -175,7 +175,7 @@ public interface Operation { * * @return the response code retrieved from the server * - * @exception IOException if an error occurred in the transport layer during + * @throws IOException if an error occurred in the transport layer during * the transaction; if this object was created by an OBEX server */ public int getResponseCode() throws IOException; diff --git a/obex/javax/obex/PasswordAuthentication.java b/obex/javax/obex/PasswordAuthentication.java index 82f9623..49833fe 100644 --- a/obex/javax/obex/PasswordAuthentication.java +++ b/obex/javax/obex/PasswordAuthentication.java @@ -35,7 +35,7 @@ package javax.obex; /** * This class holds user name and password combinations. * - * @version 0.3 November 28, 2008 + * @hide */ public class PasswordAuthentication { diff --git a/obex/javax/obex/PrivateInputStream.java b/obex/javax/obex/PrivateInputStream.java index 1b83bb0..4d8a537 100644 --- a/obex/javax/obex/PrivateInputStream.java +++ b/obex/javax/obex/PrivateInputStream.java @@ -32,7 +32,8 @@ package javax.obex; -import java.io.*; +import java.io.InputStream; +import java.io.IOException; /** * This object provides an input stream to the Operation objects used in this @@ -40,7 +41,7 @@ import java.io.*; * * OPTIMIZATION: Include the other read() methods defined in InputStream. * - * @version 0.3 November 28, 2008 + * @hide */ public class PrivateInputStream extends InputStream { @@ -77,7 +78,7 @@ public class PrivateInputStream extends InputStream { * @return the number of bytes that can be read from this input stream * without blocking * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override public synchronized int available() throws IOException { @@ -95,7 +96,7 @@ public class PrivateInputStream extends InputStream { * @return the byte read from the input stream or -1 if it reaches the end * of stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override public synchronized int read() throws IOException { @@ -173,7 +174,7 @@ public class PrivateInputStream extends InputStream { /** * Verifies that this stream is open * - * @exception IOException if the stream is not open + * @throws IOException if the stream is not open */ private void ensureOpen() throws IOException { parent.ensureOpen(); @@ -186,7 +187,7 @@ public class PrivateInputStream extends InputStream { * Closes the input stream. If the input stream is already closed, do * nothing. * - * @exception IOException this will never happen + * @throws IOException this will never happen */ @Override public void close() throws IOException { diff --git a/obex/javax/obex/PrivateOutputStream.java b/obex/javax/obex/PrivateOutputStream.java index 03d2363..75220d6 100644 --- a/obex/javax/obex/PrivateOutputStream.java +++ b/obex/javax/obex/PrivateOutputStream.java @@ -32,13 +32,15 @@ package javax.obex; -import java.io.*; +import java.io.IOException; +import java.io.OutputStream; +import java.io.ByteArrayOutputStream; /** * This object provides an output stream to the Operation objects used in this * package. * - * @version 0.3 November 28, 2008 + * @hide */ class PrivateOutputStream extends OutputStream { @@ -78,7 +80,7 @@ class PrivateOutputStream extends OutputStream { * * @param b the byte to write * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override public synchronized void write(int b) throws IOException { @@ -164,7 +166,7 @@ class PrivateOutputStream extends OutputStream { /** * Verifies that this stream is open * - * @exception IOException if the stream is not open + * @throws IOException if the stream is not open */ private void ensureOpen() throws IOException { parent.ensureOpen(); @@ -177,7 +179,7 @@ class PrivateOutputStream extends OutputStream { * Closes the output stream. If the input stream is already closed, do * nothing. * - * @exception IOException this will never happen + * @throws IOException this will never happen */ @Override public void close() throws IOException { diff --git a/obex/javax/obex/ResponseCodes.java b/obex/javax/obex/ResponseCodes.java index 7496738..2d7627b 100644 --- a/obex/javax/obex/ResponseCodes.java +++ b/obex/javax/obex/ResponseCodes.java @@ -52,7 +52,7 @@ package javax.obex; * client wishes to access a database, database table, or database record that * has been locked. * - * @version 0.3 November 28, 2008 + * @hide */ public class ResponseCodes { @@ -318,7 +318,5 @@ public class ResponseCodes { /** * Constructor does nothing. */ - private ResponseCodes() { - throw new RuntimeException("Not Implemented! Used to compile Code"); - } + private ResponseCodes() {} } diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java index 1b9c4e9..bb3490b 100644 --- a/obex/javax/obex/ServerOperation.java +++ b/obex/javax/obex/ServerOperation.java @@ -54,7 +54,7 @@ import java.io.ByteArrayOutputStream; * OPTIMIZATION: Extend the ClientOperation and reuse the methods defined * OPTIMIZATION: in that class. * - * @version 0.3 November 28, 2008 + * @hide */ public class ServerOperation implements Operation, BaseStream { @@ -70,11 +70,12 @@ public class ServerOperation implements Operation, BaseStream { boolean finalBitSet; - private boolean endOfBody; // This variable defines when the end of body - + // This variable defines when the end of body // header has been received. When this header // is received, no further body data will be // received from the client + private boolean endOfBody; + private boolean isGet; boolean isAborted; @@ -95,9 +96,7 @@ public class ServerOperation implements Operation, BaseStream { private boolean requestFinished; - private static int BASE_PACKET_LENGTH = 3; - - private static final String TAG = "ServerOperation"; + private static final int BASE_PACKET_LENGTH = 3; private boolean isHasBody; @@ -116,7 +115,7 @@ public class ServerOperation implements Operation, BaseStream { * * @param listen the listener that is responding to the request * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public ServerOperation(ServerSession p, InputStream in, int request, int maxSize, ServerRequestHandler listen) throws IOException { @@ -168,7 +167,7 @@ public class ServerOperation implements Operation, BaseStream { /* * Determine if the packet length is larger than this device can receive */ - if (length > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (length > ObexHelper.MAX_PACKET_SIZE_INT) { parent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null); throw new IOException("Packet received was too large"); } @@ -184,14 +183,14 @@ public class ServerOperation implements Operation, BaseStream { bytesReceived += in.read(data, bytesReceived, data.length - bytesReceived); } - byte[] body = OBEXHelper.updateHeaderSet(requestHeaders, data); + byte[] body = ObexHelper.updateHeaderSet(requestHeaders, data); if (body != null) { isHasBody = true; } if (requestHeaders.connectionID != null) { - listener.setConnectionID(OBEXHelper.convertToLong(requestHeaders.connectionID)); + listener.setConnectionID(ObexHelper.convertToLong(requestHeaders.connectionID)); } else { listener.setConnectionID(0); } @@ -232,7 +231,7 @@ public class ServerOperation implements Operation, BaseStream { privateInput.writeBytes(body, 1); } else { while ((!isGet) && (!finalBitSet)) { - sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + sendReply(ObexHelper.OBEX_HTTP_CONTINUE); if (privateInput.available() > 0) { break; } @@ -242,7 +241,7 @@ public class ServerOperation implements Operation, BaseStream { }// if (length > 3) while ((!isGet) && (!finalBitSet) && (privateInput.available() == 0)) { - sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + sendReply(ObexHelper.OBEX_HTTP_CONTINUE); if (privateInput.available() > 0) { break; } @@ -250,7 +249,7 @@ public class ServerOperation implements Operation, BaseStream { // wait for get request finished !!!! while (isGet && !finalBitSet) { - sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + sendReply(ObexHelper.OBEX_HTTP_CONTINUE); } if (finalBitSet && isGet) { requestFinished = true; @@ -279,11 +278,11 @@ public class ServerOperation implements Operation, BaseStream { if (!isGet) { if (!finalBitSet) { if (sendEmpty) { - sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + sendReply(ObexHelper.OBEX_HTTP_CONTINUE); return true; } else { if ((responseSize > 3) || (privateOutput.size() > 0)) { - sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + sendReply(ObexHelper.OBEX_HTTP_CONTINUE); return true; } else { return false; @@ -293,7 +292,7 @@ public class ServerOperation implements Operation, BaseStream { return false; } } else { - sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + sendReply(ObexHelper.OBEX_HTTP_CONTINUE); return true; } } @@ -308,7 +307,7 @@ public class ServerOperation implements Operation, BaseStream { * false if no reply was received because the operation ended, * an abort was received, or the final bit was set in the reply * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ protected synchronized boolean sendReply(int type) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -318,10 +317,10 @@ public class ServerOperation implements Operation, BaseStream { if (id == -1) { replyHeaders.connectionID = null; } else { - replyHeaders.connectionID = OBEXHelper.convertToByteArray(id); + replyHeaders.connectionID = ObexHelper.convertToByteArray(id); } - byte[] headerArray = OBEXHelper.createHeader(replyHeaders, true); + byte[] headerArray = ObexHelper.createHeader(replyHeaders, true); int bodyLength = -1; int orginalBodyLength = -1; @@ -336,7 +335,7 @@ public class ServerOperation implements Operation, BaseStream { int start = 0; while (end != headerArray.length) { - end = OBEXHelper.findHeaderEnd(headerArray, start, maxPacketLength + end = ObexHelper.findHeaderEnd(headerArray, start, maxPacketLength - BASE_PACKET_LENGTH); if (end == -1) { @@ -434,7 +433,7 @@ public class ServerOperation implements Operation, BaseStream { responseSize = 3; parent.sendResponse(type, out.toByteArray()); - if (type == OBEXConstants.OBEX_HTTP_CONTINUE) { + if (type == ObexHelper.OBEX_HTTP_CONTINUE) { int headerID = socketInput.read(); int length = socketInput.read(); length = (length << 8) + socketInput.read(); @@ -475,7 +474,7 @@ public class ServerOperation implements Operation, BaseStream { /* * Determine if the packet length is larger then this device can receive */ - if (length > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (length > ObexHelper.MAX_PACKET_SIZE_INT) { parent.sendResponse(ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE, null); throw new IOException("Packet received was too large"); } @@ -491,12 +490,12 @@ public class ServerOperation implements Operation, BaseStream { bytesReceived += socketInput.read(data, bytesReceived, data.length - bytesReceived); } - byte[] body = OBEXHelper.updateHeaderSet(requestHeaders, data); + byte[] body = ObexHelper.updateHeaderSet(requestHeaders, data); if (body != null) { isHasBody = true; } if (requestHeaders.connectionID != null) { - listener.setConnectionID(OBEXHelper + listener.setConnectionID(ObexHelper .convertToLong(requestHeaders.connectionID)); } else { listener.setConnectionID(1); @@ -547,7 +546,7 @@ public class ServerOperation implements Operation, BaseStream { * corresponding input and output streams will be closed along with this * object. * - * @exception IOException if the transaction has already ended or if an + * @throws IOException if the transaction has already ended or if an * OBEX server called this method */ public void abort() throws IOException { @@ -561,7 +560,7 @@ public class ServerOperation implements Operation, BaseStream { * * @return the headers received during this Operation * - * @exception IOException if this Operation has been closed + * @throws IOException if this Operation has been closed */ public HeaderSet getReceivedHeaders() throws IOException { ensureOpen(); @@ -574,10 +573,10 @@ public class ServerOperation implements Operation, BaseStream { * * @param headers the headers to send in the next message * - * @exception IOException if this Operation has been closed + * @throws IOException if this Operation has been closed * or the transaction has ended and no further messages will be exchanged * - * @exception IllegalArgumentException if headers was not created + * @throws IllegalArgumentException if headers was not created * by a call to ServerRequestHandler.createHeaderSet() */ public void sendHeaders(HeaderSet headers) throws IOException { @@ -602,7 +601,7 @@ public class ServerOperation implements Operation, BaseStream { * * @return the response code retrieved from the server * - * @exception IOException if an error occurred in the transport layer during + * @throws IOException if an error occurred in the transport layer during * the transaction; if this method is called on a HeaderSet * object created by calling createHeaderSet in a * ClientSession object; if this is called from a server @@ -667,7 +666,7 @@ public class ServerOperation implements Operation, BaseStream { * * @return an input stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public InputStream openInputStream() throws IOException { ensureOpen(); @@ -679,7 +678,7 @@ public class ServerOperation implements Operation, BaseStream { * * @return an input stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); @@ -690,7 +689,7 @@ public class ServerOperation implements Operation, BaseStream { * * @return an output stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public OutputStream openOutputStream() throws IOException { ensureOpen(); @@ -713,7 +712,7 @@ public class ServerOperation implements Operation, BaseStream { * * @return an output stream * - * @exception IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); @@ -722,7 +721,7 @@ public class ServerOperation implements Operation, BaseStream { /** * Closes the connection and ends the transaction * - * @exception IOException if the operation has already ended or is closed + * @throws IOException if the operation has already ended or is closed */ public void close() throws IOException { ensureOpen(); @@ -732,7 +731,7 @@ public class ServerOperation implements Operation, BaseStream { /** * Verifies that the connection is open and no exceptions should be thrown. * - * @exception IOException if an exception needs to be thrown + * @throws IOException if an exception needs to be thrown */ public void ensureOpen() throws IOException { if (exceptionString != null) { @@ -751,7 +750,7 @@ public class ServerOperation implements Operation, BaseStream { * anything on the server side since the operation of the Operation object * is not done until after the handler returns from its method. * - * @exception IOException if the operation is completed + * @throws IOException if the operation is completed */ public void ensureNotDone() throws IOException { } @@ -764,7 +763,7 @@ public class ServerOperation implements Operation, BaseStream { * @param inStream true if the input stream is closed; * false if the output stream is closed * - * @exception IOException if an IO error occurs + * @throws IOException if an IO error occurs */ public void streamClosed(boolean inStream) throws IOException { diff --git a/obex/javax/obex/ServerRequestHandler.java b/obex/javax/obex/ServerRequestHandler.java index 4e7f5b4..955e916 100644 --- a/obex/javax/obex/ServerRequestHandler.java +++ b/obex/javax/obex/ServerRequestHandler.java @@ -67,7 +67,7 @@ package javax.obex; * a CREATE-EMPTY request, there will be no Body data to read. Therefore, * a call to InputStream.read() will return -1. * - * @version 0.3 November 28, 2008 + * @hide */ public class ServerRequestHandler { @@ -99,7 +99,7 @@ public class ServerRequestHandler { * @param id the connection ID to use; -1 if no connection ID should be * sent * - * @exception IllegalArgumentException if id is not in the + * @throws IllegalArgumentException if id is not in the * range -1 to 232-1 */ public void setConnectionID(long id) { diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java index 31c82cc..9daa6c0 100644 --- a/obex/javax/obex/ServerSession.java +++ b/obex/javax/obex/ServerSession.java @@ -32,18 +32,19 @@ package javax.obex; -import java.io.*; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; /** * This class in an implementation of the ServerSession interface. * - * @version 0.3 November 28, 2008 + * @hide */ public class ServerSession implements Runnable, ObexSession { private ObexTransport client; - // private Socket client ; private InputStream input; private OutputStream output; @@ -58,9 +59,7 @@ public class ServerSession implements Runnable, ObexSession { byte[] challengeDigest; - public boolean isClosed; - - private static final String TAG = "ServerSession"; + private boolean isClosed; /** * Creates new ServerSession. @@ -74,7 +73,7 @@ public class ServerSession implements Runnable, ObexSession { * @param auth * the authenticator to use with this connection * - * @exception IOException + * @throws IOException * if an error occurred while opening the input and output * streams */ @@ -198,7 +197,7 @@ public class ServerSession implements Runnable, ObexSession { * @param type * the type of request received; either 0x02 or 0x82 * - * @exception IOException + * @throws IOException * if an error occurred at the transport layer */ private void handlePutRequest(int type) throws IOException { @@ -217,7 +216,7 @@ public class ServerSession implements Runnable, ObexSession { } else if (!client.isAborted) { // wait for the final bit while (!client.finalBitSet) { - client.sendReply(OBEXConstants.OBEX_HTTP_CONTINUE); + client.sendReply(ObexHelper.OBEX_HTTP_CONTINUE); } client.sendReply(response); } @@ -240,7 +239,7 @@ public class ServerSession implements Runnable, ObexSession { * @param type * the type of request received; either 0x03 or 0x83 * - * @exception IOException + * @throws IOException * if an error occurred at the transport layer */ private void handleGetRequest(int type) throws IOException { @@ -265,7 +264,7 @@ public class ServerSession implements Runnable, ObexSession { * @param header * the headers to include in the response * - * @exception IOException + * @throws IOException * if an IO error occurs */ protected void sendResponse(int code, byte[] header) throws IOException { @@ -297,7 +296,7 @@ public class ServerSession implements Runnable, ObexSession { * request, this method will create a reply message to send to the server * with the response code provided. * - * @exception IOException + * @throws IOException * if an error occurred at the transport layer */ private void handleSetPathRequest() throws IOException { @@ -316,7 +315,7 @@ public class ServerSession implements Runnable, ObexSession { flags = input.read(); constants = input.read(); - if (length > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (length > ObexHelper.MAX_PACKET_SIZE_INT) { code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; totalLength = 3; } else { @@ -329,10 +328,10 @@ public class ServerSession implements Runnable, ObexSession { - bytesReceived); } - OBEXHelper.updateHeaderSet(request, headers); + ObexHelper.updateHeaderSet(request, headers); if (request.connectionID != null) { - listener.setConnectionID(OBEXHelper.convertToLong(request.connectionID)); + listener.setConnectionID(ObexHelper.convertToLong(request.connectionID)); } else { listener.setConnectionID(-1); } @@ -341,7 +340,7 @@ public class ServerSession implements Runnable, ObexSession { if (request.authResp != null) { if (!handleAuthResp(request.authResp)) { code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; - listener.onAuthenticationFailure(OBEXHelper.getTagValue((byte)0x01, + listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, request.authResp)); } request.authResp = null; @@ -387,10 +386,10 @@ public class ServerSession implements Runnable, ObexSession { if (id == -1) { reply.connectionID = null; } else { - reply.connectionID = OBEXHelper.convertToByteArray(id); + reply.connectionID = ObexHelper.convertToByteArray(id); } - head = OBEXHelper.createHeader(reply, false); + head = ObexHelper.createHeader(reply, false); totalLength += head.length; if (totalLength > maxPacketLength) { @@ -424,7 +423,7 @@ public class ServerSession implements Runnable, ObexSession { * ServerRequestHandler object. After the handler processes the * request, this method will create a reply message to send to the server. * - * @exception IOException + * @throws IOException * if an error occurred at the transport layer */ private void handleDisconnectRequest() throws IOException { @@ -439,7 +438,7 @@ public class ServerSession implements Runnable, ObexSession { length = input.read(); length = (length << 8) + input.read(); - if (length > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (length > ObexHelper.MAX_PACKET_SIZE_INT) { code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; totalLength = 3; } else { @@ -452,11 +451,11 @@ public class ServerSession implements Runnable, ObexSession { - bytesReceived); } - OBEXHelper.updateHeaderSet(request, headers); + ObexHelper.updateHeaderSet(request, headers); } if (request.connectionID != null) { - listener.setConnectionID(OBEXHelper.convertToLong(request.connectionID)); + listener.setConnectionID(ObexHelper.convertToLong(request.connectionID)); } else { listener.setConnectionID(1); } @@ -464,7 +463,7 @@ public class ServerSession implements Runnable, ObexSession { if (request.authResp != null) { if (!handleAuthResp(request.authResp)) { code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; - listener.onAuthenticationFailure(OBEXHelper.getTagValue((byte)0x01, + listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, request.authResp)); } request.authResp = null; @@ -498,10 +497,10 @@ public class ServerSession implements Runnable, ObexSession { if (id == -1) { reply.connectionID = null; } else { - reply.connectionID = OBEXHelper.convertToByteArray(id); + reply.connectionID = ObexHelper.convertToByteArray(id); } - head = OBEXHelper.createHeader(reply, false); + head = ObexHelper.createHeader(reply, false); totalLength += head.length; if (totalLength > maxPacketLength) { @@ -541,7 +540,7 @@ public class ServerSession implements Runnable, ObexSession { * request, this method will create a reply message to send to the server * with the response code provided. * - * @exception IOException + * @throws IOException * if an error occurred at the transport layer */ private void handleConnectRequest() throws IOException { @@ -567,11 +566,11 @@ public class ServerSession implements Runnable, ObexSession { maxPacketLength = (maxPacketLength << 8) + input.read(); // should we check it? - if (maxPacketLength > OBEXConstants.MAX_PACKET_SIZE_INT) { - maxPacketLength = OBEXConstants.MAX_PACKET_SIZE_INT; + if (maxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) { + maxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT; } - if (packetLength > OBEXConstants.MAX_PACKET_SIZE_INT) { + if (packetLength > ObexHelper.MAX_PACKET_SIZE_INT) { code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; totalLength = 7; } else { @@ -584,11 +583,11 @@ public class ServerSession implements Runnable, ObexSession { - bytesReceived); } - OBEXHelper.updateHeaderSet(request, headers); + ObexHelper.updateHeaderSet(request, headers); } if (request.connectionID != null) { - listener.setConnectionID(OBEXHelper.convertToLong(request.connectionID)); + listener.setConnectionID(ObexHelper.convertToLong(request.connectionID)); } else { listener.setConnectionID(1); } @@ -596,7 +595,7 @@ public class ServerSession implements Runnable, ObexSession { if (request.authResp != null) { if (!handleAuthResp(request.authResp)) { code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; - listener.onAuthenticationFailure(OBEXHelper.getTagValue((byte)0x01, + listener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, request.authResp)); } request.authResp = null; @@ -625,10 +624,10 @@ public class ServerSession implements Runnable, ObexSession { if (id == -1) { reply.connectionID = null; } else { - reply.connectionID = OBEXHelper.convertToByteArray(id); + reply.connectionID = ObexHelper.convertToByteArray(id); } - head = OBEXHelper.createHeader(reply, false); + head = ObexHelper.createHeader(reply, false); totalLength += head.length; if (totalLength > maxPacketLength) { @@ -647,7 +646,7 @@ public class ServerSession implements Runnable, ObexSession { } // Compute Length of OBEX CONNECT packet - byte[] length = OBEXHelper.convertToByteArray(totalLength); + byte[] length = ObexHelper.convertToByteArray(totalLength); /* * Write the OBEX CONNECT packet to the server. Byte 0: response code @@ -661,8 +660,8 @@ public class ServerSession implements Runnable, ObexSession { sendData[2] = length[3]; sendData[3] = (byte)0x10; sendData[4] = (byte)0x00; - sendData[5] = (byte)(OBEXConstants.MAX_PACKET_SIZE_INT >> 8); - sendData[6] = (byte)(OBEXConstants.MAX_PACKET_SIZE_INT & 0xFF); + sendData[5] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8); + sendData[6] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF); if (head != null) { System.arraycopy(head, 0, sendData, 7, head.length); @@ -752,9 +751,9 @@ public class ServerSession implements Runnable, ObexSession { * 0x02 is the realm, which provides a description of which user name * and password to use. */ - byte[] challenge = OBEXHelper.getTagValue((byte)0x00, header.authChall); - byte[] option = OBEXHelper.getTagValue((byte)0x01, header.authChall); - byte[] description = OBEXHelper.getTagValue((byte)0x02, header.authChall); + byte[] challenge = ObexHelper.getTagValue((byte)0x00, header.authChall); + byte[] option = ObexHelper.getTagValue((byte)0x01, header.authChall); + byte[] description = ObexHelper.getTagValue((byte)0x02, header.authChall); String realm = ""; if (description != null) { @@ -777,7 +776,7 @@ public class ServerSession implements Runnable, ObexSession { case 0xFF: // UNICODE Encoding - realm = OBEXHelper.convertToUnicode(realmString, false); + realm = ObexHelper.convertToUnicode(realmString, false); break; case 0x02: @@ -872,7 +871,7 @@ public class ServerSession implements Runnable, ObexSession { header.authResp[0] = (byte)0x00; header.authResp[1] = (byte)0x10; - System.arraycopy(OBEXHelper.computeMD5Hash(digest), 0, header.authResp, 2, 16); + System.arraycopy(ObexHelper.computeMd5Hash(digest), 0, header.authResp, 2, 16); // Add the challenge header.authResp[18] = (byte)0x02; @@ -897,7 +896,7 @@ public class ServerSession implements Runnable, ObexSession { return false; } // get the correct password from the application - byte[] correctPassword = authenticator.onAuthenticationResponse(OBEXHelper.getTagValue( + byte[] correctPassword = authenticator.onAuthenticationResponse(ObexHelper.getTagValue( (byte)0x01, authResp)); if (correctPassword == null) { return false; @@ -908,8 +907,8 @@ public class ServerSession implements Runnable, ObexSession { System.arraycopy(challengeDigest, 0, temp, 0, 16); System.arraycopy(correctPassword, 0, temp, 16, correctPassword.length); - byte[] correctResponse = OBEXHelper.computeMD5Hash(temp); - byte[] actualResponse = OBEXHelper.getTagValue((byte)0x00, authResp); + byte[] correctResponse = ObexHelper.computeMd5Hash(temp); + byte[] actualResponse = ObexHelper.getTagValue((byte)0x00, authResp); // compare the MD5 hash array . for (int i = 0; i < 16; i++) { diff --git a/obex/javax/obex/SessionNotifier.java b/obex/javax/obex/SessionNotifier.java index 0c9bfd5..fd574c0 100644 --- a/obex/javax/obex/SessionNotifier.java +++ b/obex/javax/obex/SessionNotifier.java @@ -45,7 +45,7 @@ import java.io.IOException; * ServerRequestHandler argument that will process the requests * from the client that connects to the server. * - * @version 0.3 November 28, 2008 + * @hide */ public interface SessionNotifier { @@ -86,12 +86,12 @@ public interface SessionNotifier { * * @return the connection to the client * - * @exception IOException if an error occurs in the transport layer + * @throws IOException if an error occurs in the transport layer * - * @exception NullPointerException if handler is + * @throws NullPointerException if handler is * null * - * @exception ServiceRegistrationException if the structure of the + * @throws ServiceRegistrationException if the structure of the * associated service record is invalid or if the service record * could not be added successfully to the local SDDB. The * structure of service record is invalid if the service @@ -100,7 +100,7 @@ public interface SessionNotifier { * cannot be changed. Failures to add the record to the SDDB could * be due to insufficient disk space, database locks, etc. * - * @exception BluetoothStateException if the server device could + * @throws BluetoothStateException if the server device could * not be placed in connectable mode because the device user has * configured the device to be non-connectable */ @@ -145,12 +145,12 @@ public interface SessionNotifier { * * @return the connection to the client * - * @exception IOException if an error occurs in the transport layer + * @throws IOException if an error occurs in the transport layer * - * @exception NullPointerException if handler is + * @throws NullPointerException if handler is * null * - * @exception ServiceRegistrationException if the structure of the + * @throws ServiceRegistrationException if the structure of the * associated service record is invalid or if the service record * could not be added successfully to the local SDDB. The * structure of service record is invalid if the service @@ -159,7 +159,7 @@ public interface SessionNotifier { * cannot be changed. Failures to add the record to the SDDB could * be due to insufficient disk space, database locks, etc. * - * @exception BluetoothStateException if the server device could + * @throws BluetoothStateException if the server device could * not be placed in connectable mode because the device user has * configured the device to be non-connectable */ -- cgit v1.1