diff options
Diffstat (limited to 'src/com/android/bluetooth/map/BluetoothMasObexServer.java')
-rw-r--r-- | src/com/android/bluetooth/map/BluetoothMasObexServer.java | 1122 |
1 files changed, 1122 insertions, 0 deletions
diff --git a/src/com/android/bluetooth/map/BluetoothMasObexServer.java b/src/com/android/bluetooth/map/BluetoothMasObexServer.java new file mode 100644 index 000000000..a24a91235 --- /dev/null +++ b/src/com/android/bluetooth/map/BluetoothMasObexServer.java @@ -0,0 +1,1122 @@ +/* + * Copyright (c) 2010-2011, Code Aurora Forum. 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 Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 com.android.bluetooth.map; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; + +import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Message; +import android.text.format.Time; +import android.util.Log; + +import javax.obex.*; + + +import com.android.bluetooth.map.BluetoothMasAppIf.BluetoothMasMessageListingRsp; +import com.android.bluetooth.map.BluetoothMasAppIf.BluetoothMasMessageRsp; +import com.android.bluetooth.map.BluetoothMasAppIf.BluetoothMasPushMsgRsp; + + +public class BluetoothMasObexServer extends ServerRequestHandler { + + private static final String TAG = "BluetoothMasObexServer"; + + private static final boolean D = BluetoothMasService.DEBUG; + + private static final boolean V = BluetoothMasService.VERBOSE; + + private static final int UUID_LENGTH = 16; + + // type for list folder contents + private static final String TYPE_LISTING = "x-obex/folder-listing"; + private static final String TYPE_MESSAGE_LISTING = "x-bt/MAP-msg-listing"; + private static final String TYPE_MESSAGE = "x-bt/message"; + private static final String TYPE_MESSAGE_STATUS = "x-bt/messageStatus"; + private static final String TYPE_MESSAGE_UPDATE = "x-bt/MAP-messageUpdate"; + private static final String TYPE_MESSAGE_NOTIFICATION = "x-bt/MAP-NotificationRegistration"; + + public long mConnectionId; + + private Handler mCallback = null; + + public Context mContext; + + public static boolean sIsAborted = false; + + public enum MasState { + MAS_SERVER_CONNECTING, + MAS_SERVER_DISCONNECTING, + MAS_SERVER_CONNECTED, + MAS_SERVER_DISCONNECTED, + MAS_SERVER_SET_FOLDER, + MAS_SERVER_GET_FILE_PENDING, + MAS_SERVER_BROWSE_FOLDER_PENDING, + MAS_SERVER_BROWSE_FOLDER, + MAS_SERVER_GET_MSG_LIST_PENDING, + MAS_SERVER_GET_MSG_LIST, + MAS_SERVER_GET_MSG_PENDING, + MAS_SERVER_GET_MSG, + MAS_SERVER_SET_MSG_STATUS, + MAS_SERVER_SET_NOTIFICATION_REG, + MAS_SERVER_UPDATE_INBOX, + MAS_SERVER_PUSH_MESSAGE + }; + private static MasState state = MasState.MAS_SERVER_DISCONNECTED; + + // 128 bit UUID for MAS + private static final byte[] MAS_TARGET = new byte[] { + (byte)0xbb, (byte)0x58, (byte)0x2b, (byte)0x40, (byte)0x42, (byte)0x0c, (byte)0x11, (byte)0xdb, + (byte)0xb0, (byte)0xde, (byte)0x08, (byte)0x00, (byte)0x20, (byte)0x0c, (byte)0x9a, (byte)0x66 + }; + + private BluetoothMasAppIf appIf; + + private BluetoothDevice mRemoteDevice; + + private class MasAppParamsStore { + + private BluetoothMasAppParams appParams = null; + + public final void clear() { + if (D) Log.d(TAG, "Clear AppParams : Enter"); + appParams.MaxListCount = BluetoothMasSpecParams.MAS_DEFAULT_MAX_LIST_COUNT; + appParams.ListStartOffset = 0; + appParams.SubjectLength = BluetoothMasSpecParams.MAS_DEFAULT_SUBJECT_LENGTH; + appParams.ParameterMask = BluetoothMasSpecParams.MAS_DEFAULT_PARAMETER_MASK; + appParams.FilterMessageType = 0; + appParams.FilterReadStatus = 0; + appParams.FilterPriority = 0; + appParams.FilterPeriodBegin = null; + appParams.FilterPeriodEnd = null; + appParams.FilterRecipient = null; + appParams.FilterOriginator = null; + appParams.Retry = 1; + appParams.Transparent = 0; + appParams.FractionRequest = BluetoothMasSpecParams.MAS_FRACTION_REQUEST_NOT_SET; + appParams.Charset = 0x01; + } + + public MasAppParamsStore() { + super(); + appParams = new BluetoothMasAppParams(); + clear(); + } + + public final BluetoothMasAppParams get() { + if (D) Log.d(TAG, "Create MasAppParams struct for service : Enter"); + BluetoothMasAppParams tmp = new BluetoothMasAppParams(); + + tmp.MaxListCount = appParams.MaxListCount; + tmp.ListStartOffset = appParams.ListStartOffset; + tmp.SubjectLength = appParams.SubjectLength; + tmp.ParameterMask = appParams.ParameterMask; + + tmp.Attachment = appParams.Attachment; + tmp.Charset = appParams.Charset; + + tmp.StatusIndicator = appParams.StatusIndicator; + tmp.StatusValue = appParams.StatusValue; + tmp.Retry = appParams.Retry; + + tmp.FilterMessageType = appParams.FilterMessageType; + tmp.FilterReadStatus = appParams.FilterReadStatus; + tmp.FilterPriority = appParams.FilterPriority; + + tmp.FilterPeriodBegin = (appParams.FilterPeriodBegin == null) ? null : new String(appParams.FilterPeriodBegin); + tmp.FilterPeriodEnd = (appParams.FilterPeriodEnd == null) ? null : new String(appParams.FilterPeriodEnd); + tmp.FilterRecipient = (appParams.FilterRecipient == null) ? null : new String(appParams.FilterRecipient); + tmp.FilterOriginator = (appParams.FilterOriginator == null) ? null : new String(appParams.FilterOriginator); + tmp.Retry = appParams.Retry; + tmp.Transparent = appParams.Transparent; + tmp.FractionRequest = appParams.FractionRequest; + tmp.Notification = appParams.Notification; + + return tmp; + } + + public final boolean isMaxListCountZero() { + + return (appParams.MaxListCount == 0) ? true : false; + + } + + private final int getUint16BigEndian(byte b1, byte b2) { + int retVal; + retVal = (int) ((0x0000FF00 & (int) (b1 << 0x8)) | (0x000000FF & (int) b2)); + return retVal; + } + + private final long getUint32BigEndian(byte b1, byte b2, byte b3, byte b4) { + long retVal; + retVal = (long) ((0xFF000000 & (long) (b1 << 0x24)) + | (0x00FF0000 & (long) (b2 << 0x16)) + | (0x0000FF00 & (long) (b3 << 0x8)) | (0x000000FF & (long) b4)); + return retVal; + } + + private final boolean validateTag(long tagVal, long tagLen, long tagMinVal, long tagMaxVal, long tagActualLen) { + + if (tagLen != tagActualLen) { + return false; + } + + if ( tagVal < tagMinVal || tagVal > tagMaxVal){ + return false; + } + return true; + } + + public final boolean parse(byte[] params) { + int i = 0; + + + if (D) Log.d(TAG, "Parse App. Params: Enter"); + + if (params == null){ + if (D) Log.d(TAG, "No App. Params to parse: Exit"); + return true; + } + + while (i < params.length) { + switch (params[i]) { + case BluetoothMasSpecParams.MAS_TAG_MAX_LIST_COUNT: + i += 2; + appParams.MaxListCount = getUint16BigEndian(params[i], params[i + 1]); + Log.d(TAG, " params i " + params[i] + " params i+1" + + params[i + 1] + " maxlistcount " + + appParams.MaxListCount); + if(validateTag((long)appParams.MaxListCount, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_MAX_LIST_COUNT_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_MAX_LIST_COUNT_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_MAX_LIST_COUNT_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_MAX_LIST_COUNT_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_LIST_START_OFFSET: + i += 2; + appParams.ListStartOffset = getUint16BigEndian(params[i], + params[i + 1]); + Log.d(TAG, " params i " + params[i] + " params i+1" + + params[i + 1] + " maxlistcount " + + appParams.ListStartOffset); + if(validateTag((long)appParams.ListStartOffset, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_LIST_START_OFFSET_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_LIST_START_OFFSET_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_LIST_START_OFFSET_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_LIST_START_OFFSET_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_PERIOD_BEGIN: + i += 1; + appParams.FilterPeriodBegin = new String(""); + for (int j = 1; j < params[i]; j++) { + appParams.FilterPeriodBegin += (char) params[i + j]; + } + Log.d(TAG, "FilterPeriodBegin " + + appParams.FilterPeriodBegin); + i += params[i]; + i += 1; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_PERIOD_END: + i += 1; + appParams.FilterPeriodEnd = new String(""); + for (int j = 1; j < params[i]; j++) { + appParams.FilterPeriodEnd += (char) params[i + j]; + } + Log.d(TAG, "FilterPeriodEnd " + appParams.FilterPeriodEnd); + i += params[i]; + i += 1; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_RECIPIENT: + i += 1; + appParams.FilterRecipient = new String(""); + for (int j = 1; j < params[i]; j++) { + appParams.FilterRecipient += (char)params[i + j]; + + } + Log.d(TAG, "FilterPeriodRecipient " + + appParams.FilterRecipient); + i += params[i]; + i += 1; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_ORIGINATOR: + i += 1; + appParams.FilterOriginator = new String(""); + for (int j = 1; j < params[i]; j++) { + appParams.FilterOriginator += (char) params[i+ j]; + } + Log.d(TAG, "FilterPeriodOriginator " + + appParams.FilterOriginator); + i += params[i]; + i += 1; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_MESSAGE_TYPE: + i += 2; + appParams.FilterMessageType = params[i]; + Log.d(TAG, " params i " + params[i] + " FilterMessageType " + + appParams.FilterMessageType); + if(validateTag((long)appParams.FilterMessageType, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_MESSAGE_TYPE_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_MESSAGE_TYPE_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_MESSAGE_TYPE_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_FILTER_MESSAGE_TYPE_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_READ_STATUS: + i += 2; + appParams.FilterReadStatus = params[i]; + Log.d(TAG, " params i " + params[i] + " FilterReadStatus " + + appParams.FilterReadStatus); + if(validateTag((long)appParams.FilterReadStatus, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_READ_STATUS_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_READ_STATUS_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_READ_STATUS_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_FILTER_READ_STATUS_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_FILTER_PRIORITY: + i += 2; + appParams.FilterPriority = params[i]; + Log.d(TAG, " params i " + params[i] + " FilterPriority " + + appParams.FilterPriority); + if(validateTag((long)appParams.FilterPriority, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_PRIORITY_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_PRIORITY_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FILTER_PRIORITY_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_FILTER_PRIORITY_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_STATUS_INDICATOR: + i += 2; + appParams.StatusIndicator = params[i]; + Log.d(TAG, " params i " + params[i] + " StatusIndicator " + + appParams.StatusIndicator); + if(validateTag((long)appParams.StatusIndicator, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_STATUS_INDICATOR_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_STATUS_INDICATOR_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_STATUS_INDICATOR_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_STATUS_INDICATOR_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_STATUS_VALUE: + i += 2; + appParams.StatusValue = params[i]; + Log.d(TAG, " params i " + params[i] + " StatusValue " + + appParams.StatusValue); + if(validateTag((long)appParams.StatusValue, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_STATUS_VALUE_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_STATUS_VALUE_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_STATUS_VALUE_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_STATUS_VALUE_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_SUBJECT_LENGTH: + i += 2; + appParams.SubjectLength = (short)(params[i] & 0x00FF); + Log.d(TAG, " params i " + params[i] + " SubjectLen " + + appParams.SubjectLength); + if(validateTag((long)appParams.SubjectLength, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_SUBJECT_LENGTH_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_SUBJECT_LENGTH_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_SUBJECT_LENGTH_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_SUBJECT_LENGTH_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_PARAMETER_MASK: + i += 2; + appParams.ParameterMask = getUint32BigEndian(params[i], + params[i + 1], params[i + 2], params[i + 3]); + if ( appParams.ParameterMask == 0 ){ + // If it is 0, send all parameters + appParams.ParameterMask = BluetoothMasSpecParams.MAS_DEFAULT_PARAMETER_MASK; + } + Log.d(TAG, " params i " + params[i] + " params i+1" + + params[i + 1] + "params[i+2]" + params[i + 2] + + "params[i+3" + params[i + 3] + " ParameterMask " + + appParams.ParameterMask); + if(validateTag((long)appParams.ParameterMask, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_PARAMETER_MASK_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_PARAMETER_MASK_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_PARAMETER_MASK_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_PARAMETER_MASK_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_CHARSET: + i += 2; + appParams.Charset = params[i]; + Log.d(TAG, " params i " + params[i] + " Charset " + + appParams.Charset); + if(validateTag((long)appParams.Charset, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_CHARSET_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_CHARSET_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_CHARSET_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_CHARSET_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_TRANSPARENT: + i += 2; + appParams.Transparent = params[i]; + Log.d(TAG, " params i " + params[i] + " Transparent " + + appParams.Transparent); + if(validateTag((long)appParams.Transparent, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_TRANSPARENT_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_TRANSPARENT_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_TRANSPARENT_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_TRANSPARENT_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_RETRY: + i += 2; + appParams.Retry = params[i]; + Log.d(TAG, " params i " + params[i] + " Retry " + + appParams.Retry); + if(validateTag((long)appParams.Retry, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_RETRY_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_RETRY_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_RETRY_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_RETRY_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_ATTACHMENT: + i += 2; + appParams.Attachment = params[i]; + Log.d(TAG, " params i " + params[i] + " Attachment " + + appParams.Attachment); + if(validateTag((long)appParams.Attachment, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_ATTACHMENT_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_ATTACHMENT_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_ATTACHMENT_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_ATTACHMENT_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_FRACTION_REQUEST: + i += 2; + appParams.FractionRequest = params[i]; + Log.d(TAG, " params i " + params[i] + " Fraction Request " + + appParams.FractionRequest); + if(validateTag((long)appParams.FractionRequest, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_FRACTION_REQUEST_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FRACTION_REQUEST_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_FRACTION_REQUEST_LEN ) == false){ + return false; + } + i += BluetoothMasSpecParams.MAS_TAG_FRACTION_REQUEST_LEN; + break; + + case BluetoothMasSpecParams.MAS_TAG_NOTIFICATION_STATUS: + i += 2; + appParams.Notification = params[i]; + if(validateTag((long)appParams.MaxListCount, (long) params[i-1], + (long) BluetoothMasSpecParams.MAS_TAG_NOTIFICATION_STATUS_MIN_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_NOTIFICATION_STATUS_MAX_VAL, + (long) BluetoothMasSpecParams.MAS_TAG_NOTIFICATION_STATUS_LEN ) == false){ + return false; + + } + i += BluetoothMasSpecParams.MAS_TAG_NOTIFICATION_STATUS_LEN; + break; + default: + break; + + } + } + return true; + } + } + + private MasAppParamsStore masAppParams = new MasAppParamsStore(); + + public BluetoothMasObexServer(Handler callback, + BluetoothDevice remoteDevice, Context context) { + super(); + appIf = new BluetoothMasAppIf(context, "SMS_MMS_EMAIL"); + mConnectionId = -1; + mCallback = callback; + mContext = context; + mRemoteDevice = remoteDevice; + + Log.d(TAG, "BlueoothMasObexServer const called"); + // set initial value when ObexServer created + if (D) Log.d(TAG, "Initialize MasObexServer"); + } + + @Override + public int onConnect(final HeaderSet request, HeaderSet reply) { + if (D) Log.d(TAG, "onConnect()"); + try { + byte[] uuid = (byte[]) request.getHeader(HeaderSet.TARGET); + if (uuid == null) { + Log.w(TAG, "Null UUID "); + return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; + } + if (D) + Log.d(TAG, "onConnect(): uuid=" + Arrays.toString(uuid)); + + if (uuid.length != UUID_LENGTH) { + Log.w(TAG, "Wrong UUID length"); + return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; + } + for (int i = 0; i < UUID_LENGTH; i++) { + if (uuid[i] != MAS_TARGET[i]) { + Log.w(TAG, "Wrong UUID"); + return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; + } + } + reply.setHeader(HeaderSet.WHO, uuid); + } catch (IOException e) { + Log.e(TAG, e.toString()); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + + try { + byte[] remote = (byte[]) request.getHeader(HeaderSet.WHO); + if (remote != null) { + if (D) Log.d(TAG, "onConnect(): remote=" + Arrays.toString(remote)); + reply.setHeader(HeaderSet.TARGET, remote); + } + } catch (IOException e) { + Log.e(TAG, e.toString()); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + + if (V) Log.v(TAG, "onConnect(): uuid is ok, will send out " + + "MSG_SESSION_ESTABLISHED msg."); + + Message msg = Message.obtain(mCallback); + msg.what = BluetoothMasService.MSG_SESSION_ESTABLISHED; + msg.sendToTarget(); + + state = MasState.MAS_SERVER_CONNECTED; + if (D) Log.d(TAG, "Connect(): Success"); + return ResponseCodes.OBEX_HTTP_OK; + } + + @Override + public void onDisconnect(final HeaderSet req, final HeaderSet resp) { + if (D) Log.d(TAG, "onDisconnect(): enter"); + appIf.disconnect(); + + resp.responseCode = ResponseCodes.OBEX_HTTP_OK; + if (mCallback != null) { + Message msg = Message.obtain(mCallback); + msg.what = BluetoothMasService.MSG_SESSION_DISCONNECTED; + msg.sendToTarget(); + if (V) Log.v(TAG,"onDisconnect(): msg MSG_SESSION_DISCONNECTED sent out."); + } + + // MNS Service + appIf.stopMnsSession(mRemoteDevice); + + state = MasState.MAS_SERVER_DISCONNECTED; + } + + @Override + public int onAbort(HeaderSet request, HeaderSet reply) { + if (D) Log.e(TAG, "onAbort(): enter."); + sIsAborted = true; + return ResponseCodes.OBEX_HTTP_OK; + } + + @Override + public int onSetPath(final HeaderSet request, final HeaderSet reply, + final boolean backup, final boolean create) { + + if (D) Log.e(TAG, "onSetPath(): supports SetPath request."); + + String tmpPath = null; + boolean retVal; + boolean tmpBackup = backup; + + if (tmpBackup && create) { + tmpBackup = true; + } else { + tmpBackup = false; + } + if (state != MasState.MAS_SERVER_CONNECTED) { + if (D) + Log.e(TAG, "onSetPath() Failed: Mas Server not connected"); + return ResponseCodes.OBEX_HTTP_UNAVAILABLE; + } + state = MasState.MAS_SERVER_SET_FOLDER; + + try { + tmpPath = (String) request.getHeader(HeaderSet.NAME); + } catch (IOException e) { + Log.e(TAG, "Get name header fail"); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + if (D) + Log.e(TAG, "backup=" + backup + " create=" + create + " name=" + + tmpPath); + + retVal = appIf.setPath(backup, tmpPath); + state = MasState.MAS_SERVER_CONNECTED; + if (retVal == true) { + if (V) + Log.e(TAG, "SetPath to" + tmpPath + "SUCCESS"); + return ResponseCodes.OBEX_HTTP_OK; + } else { + Log.e(TAG, "Path not found"); + return ResponseCodes.OBEX_HTTP_NOT_FOUND; + } + } + + @Override + public void onClose() { + + if (mCallback != null) { + Message msg = Message.obtain(mCallback); + msg.what = BluetoothMasService.MSG_SERVERSESSION_CLOSE; + msg.sendToTarget(); + if (D) Log.e(TAG, "onClose(): msg MSG_SERVERSESSION_CLOSE sent out."); + } + } + + @Override + public int onGet(Operation op) { + + byte[] appParams = null; + boolean retVal = true; + + if (D) Log.e(TAG, "onGet(): support GET request."); + + sIsAborted = false; + HeaderSet request = null; + String type = ""; + String name = ""; + + // TBD - IncompleteGet handling + try { + request = op.getReceivedHeader(); + type = (String) request.getHeader(HeaderSet.TYPE); + name = (String) request.getHeader(HeaderSet.NAME); + appParams = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); + } catch (IOException e) { + Log.e(TAG, "request headers error"); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + + masAppParams.clear(); + retVal = masAppParams.parse(appParams); + + if (type == null || (retVal == false) ) { + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + } + + Log.e(TAG, "type = " + type); + + if (type.equals(TYPE_LISTING)) { + return sendFolderListing(op); + } + if (type.equals(TYPE_MESSAGE_LISTING)) { + return sendMsgListing(op, name); + } + if (type.equals(TYPE_MESSAGE)) { + return sendMsg(op, name); + } + + Log.e(TAG, "get returns HTTP_BAD_REQUEST"); + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + + } + + private final int pushMsg(Operation op, String name) { + // TBD - Need to do this on a per masinstance basis + String DEFAULT_FILE = "PushMsg.txt"; + int outputBufferSize = op.getMaxPacketSize(); + int readLength = 0; + long timestamp = 0; + int position = 0; + byte[] b = new byte[outputBufferSize]; + BufferedOutputStream bos = null; + InputStream is = null; + boolean error = false; + File file = null; + BluetoothMasPushMsgRsp pMsg; + + file = new File(mContext.getFilesDir() + "/" + DEFAULT_FILE); + + try { + is = op.openInputStream(); + } catch (IOException e1) { + Log.e(TAG, "Error while opening InputStream"); + error = true; + } + + if (error != true) { + try { + + FileOutputStream fos = mContext.openFileOutput(DEFAULT_FILE, + Context.MODE_PRIVATE); + + bos = new BufferedOutputStream(fos); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + if (error != true) { + try { + while (true) { + if (V) { + timestamp = System.currentTimeMillis(); + } + readLength = is.read(b); + if (readLength == -1) { + if (D) { + Log.d(TAG, "Receive file reached stream end at position" + position); + } + break; + } + bos.write(b, 0, readLength); + position += readLength; + if (V) { + Log.v(TAG, "Receive file position = " + position + + " readLength " + readLength + " bytes took " + + (System.currentTimeMillis() - timestamp) + + " ms"); + } + } + } catch (IOException e1) { + Log.e(TAG, "Error when receiving file"); + error = true; + } + } + + if (bos != null) { + try { + bos.close(); + } catch (IOException e) { + Log.e(TAG, "Error when closing stream after send"); + error = true; + } + } + + if (error != true) { + pMsg = appIf.pushMsg(name, file, masAppParams.get()); + + if ((pMsg.msgHandle != null) + && (pMsg.response == ResponseCodes.OBEX_HTTP_OK)) { + HeaderSet reply; + reply = new HeaderSet(); + reply.setHeader(HeaderSet.NAME, pMsg.msgHandle); + return pushHeader(op, reply); + + } else { + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + } + } else { + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + } + } + + private final int msgStatus(Operation op, String name) { + if (D) Log.d(TAG, "msgStatus: Enter"); + return appIf.msgStatus(name, masAppParams.get()); + } + + private final int msgUpdate(Operation op, String name) { + if (D) Log.d(TAG, "msgUpdate: Enter"); + return appIf.msgUpdate(name, masAppParams.get()); + } + + private final int notification(Operation op) { + return appIf.notification(mRemoteDevice, masAppParams.get()); + } + + @Override + public int onPut(Operation op) { + + byte[] appParams = null; + boolean retVal = true; + BluetoothMasAppParams tmp; + + if (D) Log.d(TAG, "onPut(): support PUT request."); + + sIsAborted = false; + HeaderSet request = null; + String type = ""; + String name = ""; + + // TBD - IncompleteGet handling + try { + request = op.getReceivedHeader(); + type = (String) request.getHeader(HeaderSet.TYPE); + name = (String) request.getHeader(HeaderSet.NAME); + appParams = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); + } catch (IOException e) { + Log.e(TAG, "request headers error"); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + masAppParams.clear(); + if ( appParams != null ){ + masAppParams.parse(appParams); + } + if(type == null || retVal == false) { + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + } + + tmp = masAppParams.get(); + + if (tmp.Charset == 0x00) { + return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; + } + Log.e(TAG, "type = " + type); + + if (type.equals(TYPE_MESSAGE)) { + return pushMsg(op, name); + } + if (type.equals(TYPE_MESSAGE_STATUS)) { + return msgStatus(op, name); + } + if (type.equals(TYPE_MESSAGE_UPDATE)) { + return msgUpdate(op, name); + } + if (type.equals(TYPE_MESSAGE_NOTIFICATION)) { + return notification(op); + } + Log.e(TAG, "put returns HTTP_BAD_REQUEST"); + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + + } + + /** + */ + private final int pushHeader(final Operation op, final HeaderSet reply) { + + if (D) Log.d(TAG, "Push Header"); + if (D) Log.d(TAG, reply.toString()); + + int pushResult = ResponseCodes.OBEX_HTTP_OK; + try { + op.sendHeaders(reply); + } catch (IOException e) { + Log.e(TAG, e.toString()); + pushResult = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + if (D) Log.d(TAG, "Push Header: Exit : RetVal " + pushResult); + return pushResult; + } + + /** Function to send folder data to client */ + private final int sendFolderListingBody(Operation op, + final String folderlistString) { + + if (folderlistString == null) { + Log.e(TAG, "folderlistString is null!"); + return ResponseCodes.OBEX_HTTP_OK; + } + + int folderlistStringLen = folderlistString.length(); + if (D) Log.d(TAG, "Send Folder Listing Body: len=" + folderlistStringLen); + + OutputStream outputStream = null; + int pushResult = ResponseCodes.OBEX_HTTP_OK; + try { + outputStream = op.openOutputStream(); + } catch (IOException e) { + Log.e(TAG, "open outputstrem failed" + e.toString()); + return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + + int position = 0; + long timestamp = 0; + int outputBufferSize = op.getMaxPacketSize(); + if (V) Log.d(TAG, "outputBufferSize = " + outputBufferSize); + while (position != folderlistStringLen) { + if (sIsAborted) { + ((ServerOperation) op).isAborted = true; + sIsAborted = false; + break; + } + if (V) timestamp = System.currentTimeMillis(); + int readLength = outputBufferSize; + if (folderlistStringLen - position < outputBufferSize) { + readLength = folderlistStringLen - position; + } + String subStr = folderlistString.substring(position, position + readLength); + try { + outputStream.write(subStr.getBytes(), 0, readLength); + } catch (IOException e) { + Log.e(TAG, "write outputstream failed" + e.toString()); + pushResult = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + break; + } + if (V) { + Log.d(TAG, "Sending folderlist String position = " + position + + " readLength " + readLength + " bytes took " + + (System.currentTimeMillis() - timestamp) + " ms"); + } + position += readLength; + } + + if (V) Log.e(TAG, "Send Data complete!"); + + if (!closeStream(outputStream, op)) { + Log.e(TAG,"Send Folder Listing Body - Close output stream error! "); + pushResult = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; + } + if (V) Log.e(TAG, "Send Folder Listing Body complete! result = " + pushResult); + return pushResult; + } + + private final int sendBody(Operation op, File fileinfo) { + + Log.e(TAG, "sendFile = " + fileinfo.getName()); + int position = 0; + int readLength = 0; + int outputBufferSize = op.getMaxPacketSize(); + long timestamp = 0; + FileInputStream fileInputStream; + OutputStream outputStream; + BufferedInputStream bis; + + if (D) Log.d(TAG, "Send Body: Enter"); + try { + byte[] buffer = new byte[outputBufferSize]; + fileInputStream = new FileInputStream(fileinfo); + outputStream = op.openOutputStream(); + bis = new BufferedInputStream(fileInputStream, 0x4000); + while ((position != fileinfo.length())) { + timestamp = System.currentTimeMillis(); + if (position != fileinfo.length()) { + readLength = bis.read(buffer, 0, outputBufferSize); + } + outputStream.write(buffer, 0, readLength); + position += readLength; + if (V) { + Log.e(TAG, "Sending file position = " + position + + " readLength " + readLength + " bytes took " + + (System.currentTimeMillis() - timestamp) + " ms"); + } + } + } catch (IOException e) { + return ResponseCodes.OBEX_HTTP_BAD_REQUEST; + } + if (position == fileinfo.length()) { + if (D) Log.d(TAG, "SendBody : Exit: OK"); + return ResponseCodes.OBEX_HTTP_OK; + } + else { + if (D) Log.d(TAG, "SendBody : Exit: CONTINUE"); + return ResponseCodes.OBEX_HTTP_CONTINUE; + } + } + + /** Send a bMessage to client */ + private final int sendMsg(Operation op, String name) { + + BluetoothMasMessageRsp msg; + byte[] val = new byte[1]; + + if (D) Log.d(TAG, "SendMsg : Enter"); + msg = appIf.msg(name, masAppParams.get()); + if(msg == null || msg.rsp != ResponseCodes.OBEX_HTTP_OK) { + return msg.rsp; + } + + if(masAppParams.get().FractionRequest == 1){ + HeaderSet reply; + val[0] = msg.fractionDeliver; + ApplicationParameter ap = new ApplicationParameter(); + ap.addAPPHeader( + (byte) BluetoothMasSpecParams.MAS_TAG_FRACTION_DELIVER, + (byte) BluetoothMasSpecParams.MAS_TAG_FRACTION_DELIVER_LEN, + val); + + reply = new HeaderSet(); + reply.setHeader(HeaderSet.APPLICATION_PARAMETER, ap.getAPPparam()); + + int retVal; + retVal = pushHeader(op, reply); + if (retVal != ResponseCodes.OBEX_HTTP_OK) { + if (D) Log.d(TAG, "SendMsg : FAILED: RetVal " + retVal); + return retVal; + } + } + if (D) Log.d(TAG, "SendMsg : SUCCESS"); + return sendBody(op, msg.file); + } + + /** Send an XML format String to client for Folder listing */ + private final int sendFolderListing(Operation op) { + int folderListSize; + + if (D) Log.d(TAG, "SendFolderListing : Enter"); + folderListSize = appIf.folderListingSize(); + byte[] size = new byte[2]; + size[0] = (byte) ((folderListSize / 0x100) & 0xff); + size[1] = (byte) ((folderListSize % 0x100) & 0xff); + + HeaderSet reply; + ApplicationParameter ap = new ApplicationParameter(); + ap.addAPPHeader( + (byte) BluetoothMasSpecParams.MAS_TAG_FOLDER_LISTING_SIZE, + (byte) BluetoothMasSpecParams.MAS_TAG_FOLDER_LISTING_SIZE_LEN, + size); + reply = new HeaderSet(); + reply.setHeader(HeaderSet.APPLICATION_PARAMETER, ap.getAPPparam()); + + if (!masAppParams.isMaxListCountZero()) { + int retVal; + retVal = pushHeader(op, reply); + if (retVal != ResponseCodes.OBEX_HTTP_OK) { + if (D) Log.d(TAG, "SendFolderListing : FAILED : RetVal" + retVal); + return retVal; + } + return sendFolderListingBody(op, appIf.folderListing(masAppParams.get())); + } else { + op.noEndofBody(); + return pushHeader(op, reply); + } + } + + /** Send an XML format String to client for Message listing */ + private final int sendMsgListing(Operation op, String name) { + + byte[] val = new byte[2]; + + BluetoothMasMessageListingRsp appIfMsgListRsp = appIf.msgListing(name, + masAppParams.get()); + + if(appIfMsgListRsp == null || appIfMsgListRsp.rsp != ResponseCodes.OBEX_HTTP_OK) { + return appIfMsgListRsp.rsp; + } + + if (D) Log.d(TAG, "SendMsgListing : Enter"); + + Time time = new Time(); + time.setToNow(); + + String time3339 = time.format3339(false); + int timeStrLength = time3339.length(); + + String datetimeStr = time.toString().substring(0, 15) + + time3339.substring(timeStrLength - 6, timeStrLength - 3) + + time3339.substring(timeStrLength - 2, timeStrLength); + + byte[] MSETime = datetimeStr.getBytes(); + + HeaderSet reply; + ApplicationParameter ap = new ApplicationParameter(); + ap.addAPPHeader((byte) BluetoothMasSpecParams.MAS_TAG_MSE_TIME, + (byte) BluetoothMasSpecParams.MAS_TAG_MSE_TIME_LEN, MSETime); + val[0] = appIfMsgListRsp.newMessage; + ap.addAPPHeader((byte) BluetoothMasSpecParams.MAS_TAG_NEW_MESSAGE, + (byte) BluetoothMasSpecParams.MAS_TAG_NEW_MESSAGE_LEN, val); + + val[0] = (byte) ((appIfMsgListRsp.msgListingSize / 0x100) & 0xff); + val[1] = (byte) ((appIfMsgListRsp.msgListingSize % 0x100) & 0xff); + + ap.addAPPHeader( + (byte) BluetoothMasSpecParams.MAS_TAG_MESSAGE_LISTING_SIZE, + (byte) BluetoothMasSpecParams.MAS_TAG_MESSAGE_LISTING_SIZE_LEN, + val); + + reply = new HeaderSet(); + reply.setHeader(HeaderSet.APPLICATION_PARAMETER, ap.getAPPparam()); + + if (!masAppParams.isMaxListCountZero()) { + int retVal; + retVal = pushHeader(op, reply); + if (retVal != ResponseCodes.OBEX_HTTP_OK) { + if (D) Log.d(TAG, "SendMsgListing : Failed : RetVal " + retVal); + return retVal; + } + return sendBody(op, appIfMsgListRsp.file); + } else { + return pushHeader(op, reply); + } + } + + public static boolean closeStream(final OutputStream out, final Operation op) { + boolean returnvalue = true; + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + Log.e(TAG, "outputStream close failed" + e.toString()); + returnvalue = false; + } + try { + if (op != null) { + op.close(); + } + } catch (IOException e) { + Log.e(TAG, "operation close failed" + e.toString()); + returnvalue = false; + } + return returnvalue; + } +}; + |