diff options
author | Andre Eisenbach <andre@broadcom.com> | 2012-02-22 13:18:21 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2012-07-14 11:19:11 -0700 |
commit | e448862a47c08eb23185aaed574b39264f5005fc (patch) | |
tree | 2bc6246e3091315e77224fd798ea2fe8074ef972 /bta/ft | |
parent | a2ca4b83ab8bbbfd8d5f6693e927ed4b82094624 (diff) | |
download | external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.zip external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.gz external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.bz2 |
Initial Bluedroid stack commit
Diffstat (limited to 'bta/ft')
-rw-r--r-- | bta/ft/bta_ft_cfg.c | 86 | ||||
-rw-r--r-- | bta/ft/bta_ftc_act.c | 2062 | ||||
-rw-r--r-- | bta/ft/bta_ftc_api.c | 796 | ||||
-rw-r--r-- | bta/ft/bta_ftc_int.h | 504 | ||||
-rw-r--r-- | bta/ft/bta_ftc_main.c | 689 | ||||
-rw-r--r-- | bta/ft/bta_ftc_utils.c | 608 | ||||
-rw-r--r-- | bta/ft/bta_fts_act.c | 1523 | ||||
-rw-r--r-- | bta/ft/bta_fts_api.c | 230 | ||||
-rw-r--r-- | bta/ft/bta_fts_int.h | 287 | ||||
-rw-r--r-- | bta/ft/bta_fts_main.c | 603 | ||||
-rw-r--r-- | bta/ft/bta_fts_sdp.c | 66 | ||||
-rw-r--r-- | bta/ft/bta_fts_utils.c | 972 |
12 files changed, 8426 insertions, 0 deletions
diff --git a/bta/ft/bta_ft_cfg.c b/bta/ft/bta_ft_cfg.c new file mode 100644 index 0000000..89171e0 --- /dev/null +++ b/bta/ft/bta_ft_cfg.c @@ -0,0 +1,86 @@ +/***************************************************************************** +** +** Name: bta_ft_cfg.c +** +** Description: This file contains compile-time configurable constants +** for the BTA File Transfer Client and Server. +** +** Copyright (c) 2003-2010, Broadcom Inc., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" +#include "bta_ftc_int.h" + +/* Realm Character Set */ +#ifndef BTA_FTS_REALM_CHARSET +#define BTA_FTS_REALM_CHARSET 0 /* ASCII */ +#endif + +/* Specifies whether or not client's user id is required during obex authentication */ +#ifndef BTA_FTS_USERID_REQ +#define BTA_FTS_USERID_REQ FALSE +#endif + +#ifndef BTA_FTC_AUTO_FILE_LIST +#define BTA_FTC_AUTO_FILE_LIST TRUE +#endif + +#ifndef BTA_FTC_ABORT_TIMEOUT +#define BTA_FTC_ABORT_TIMEOUT 7000 /* 7 Secs for the low baud rates and SRM mode */ +#endif + +#ifndef BTA_FTC_STOP_TIMEOUT +#define BTA_FTC_STOP_TIMEOUT 2000 +#endif + +#ifndef BTA_FTC_SUSPEND_TIMEOUT +#define BTA_FTC_SUSPEND_TIMEOUT 10000 +#endif + +#ifndef BTA_FTC_PCE_SUPPORTED_FEAT /* mask: 1/download, 2/browsing */ +#define BTA_FTC_PCE_SUPPORTED_FEAT 0 /* 3/both, 0/PBAP PCE not supported */ +#endif + +#ifndef BTA_FTC_PCE_SERVICE_NAME +#define BTA_FTC_PCE_SERVICE_NAME "PBAP PCE" +#endif + +#ifndef BTA_FTC_2X_SUPPORTED +#define BTA_FTC_2X_SUPPORTED TRUE +#endif + +const tBTA_FT_CFG bta_ft_cfg = +{ +#if (defined BIP_INCLUDED && BIP_INCLUDED == TRUE && defined BTA_BI_INCLUDED && BTA_BI_INCLUDED == TRUE) + bta_ftc_bi_action, /* Client only */ +#else + NULL, /* Client only */ +#endif + + BTA_FTS_REALM_CHARSET, /* Server only */ + BTA_FTS_USERID_REQ, /* Server only */ + BTA_FTC_AUTO_FILE_LIST, /* Client only */ + BTA_FTC_PCE_SUPPORTED_FEAT, /* Client only */ + BTA_FTC_PCE_SERVICE_NAME, /* Client only */ + BTA_FTC_ABORT_TIMEOUT, /* Client only */ + BTA_FTC_STOP_TIMEOUT , /* Client only */ + BTA_FTC_SUSPEND_TIMEOUT /* Client only - used for 2X only */ +#if BTA_FTC_2X_SUPPORTED == TRUE +// btla-specific ++ + , 0 // [no reliable sess] /* non-0 to allow reliable session (Server Only) */ + , 0 // [no reliable sess] /* the maximum number of suspended session (Server Only) */ +// btla-specific -- + , TRUE /* TRUE to use Obex Over L2CAP (Server Only) */ + , TRUE /* TRUE to engage Single Response Mode (Server Only) */ +#else + , 0 /* non-0 to allow reliable session (Server Only) */ + , 0 /* the maximum number of suspended session (Server Only) */ + , FALSE /* TRUE to use Obex Over L2CAP (Server Only) */ + , FALSE /* TRUE to engage Single Response Mode (Server Only) */ +#endif +}; + +tBTA_FT_CFG *p_bta_ft_cfg = (tBTA_FT_CFG *)&bta_ft_cfg; + diff --git a/bta/ft/bta_ftc_act.c b/bta/ft/bta_ftc_act.c new file mode 100644 index 0000000..bdec2d3 --- /dev/null +++ b/bta/ft/bta_ftc_act.c @@ -0,0 +1,2062 @@ +/***************************************************************************** +** +** Name: bta_ftc_act.c +** +** Description: This file contains the file transfer action +** functions for the state machine. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bd.h" +#include "port_api.h" +#include "obx_api.h" +#include "goep_util.h" +#include "sdp_api.h" +#include "bta_fs_api.h" +#include "bta_ft_api.h" +#include "bta_ftc_int.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#include "btm_api.h" +#include "rfcdefs.h" +#include "utl.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +/* sdp discovery database size */ +#define BTA_FTC_DISC_SIZE 400 + + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +#if BTA_FTC_DEBUG == TRUE +static char *ftc_obx_evt_code(tOBX_EVENT evt_code); +#endif + +static void ftc_reset_cb (tBTA_FTC_CB *p_cb); +static void bta_ftc_sdp_cback(UINT16 status); + +/***************************************************************************** +** Action Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_ftc_init_open +** +** Description Initiate a connection with a peer device's service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_init_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + p_cb->obx_oper = FTC_OP_NONE; + p_cb->sec_mask = p_data->api_open.sec_mask; + p_cb->services = p_data->api_open.services; + p_cb->srm = p_data->api_open.srm; + p_cb->nonce = p_data->api_open.nonce; + bdcpy(p_cb->bd_addr, p_data->api_open.bd_addr); +} + +/******************************************************************************* +** +** Function bta_ftc_abort +** +** Description Abort an active Get or Put operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + /* Abort an active request */ + if (p_cb->obx_oper != FTC_OP_NONE) + { + p_cb->aborting = FTC_ABORT_REQ_NOT_SENT; + + /* Issue the abort request only if no request pending. + * some devices do not like out of sequence aborts even though + * the spec allows it */ + if ( !p_cb->req_pending || p_cb->first_req_pkt ) /* allow request for the first packet */ + { + + p_cb->aborting = FTC_ABORT_REQ_SENT; /* protection agains sending AbortReq twice in + certain conditions */ + OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL); + /* Start abort response timer */ + p_cb->timer_oper = FTC_TIMER_OP_ABORT; + bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, + p_bta_ft_cfg->abort_tout); + } + } +} + +/******************************************************************************* +** +** Function bta_ftc_api_action +** +** Description Send an Action command to the connected server +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_api_action(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTC_STATUS status = BTA_FTC_FAIL; + tBTA_FTC_EVT event = BTA_FTC_COPY_EVT + p_data->api_action.action; + + if (p_cb->obx_oper == FTC_OP_NONE) + { + /* TODO: we need to check the connected profile here */ + p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE); + OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_action.p_src); + if (p_data->api_action.action == BTA_FT_ACT_PERMISSION) + { + OBX_AddPermissionHdr(p_obx->p_pkt, p_data->api_action.permission[0], + p_data->api_action.permission[1], p_data->api_action.permission[2]); + } + else + { + OBX_AddUtf8DestNameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_action.p_dest); + } + + if (OBX_ActionReq(p_cb->obx_handle, p_data->api_action.action, p_obx->p_pkt) == OBX_SUCCESS) + { + status = BTA_FTC_OK; + p_cb->req_pending = TRUE; + p_cb->obx_oper = FTC_OP_COPY + p_data->api_action.action; + p_obx->p_pkt = NULL; /* OBX will free the packet */ + } + } + + if (status != BTA_FTC_OK) /* Send an error response to the application */ + { + utl_freebuf((void**)&p_obx->p_pkt); + p_cb->p_cback(event, (tBTA_FTC *)&status); + } +} + +/******************************************************************************* +** +** Function bta_ftc_obx_action_rsp +** +** Description Process the response to an action command +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_action_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_FTC_STATUS status = BTA_FTC_FAIL; + tBTA_FTC_EVT event = BTA_FTC_COPY_EVT + p_cb->obx_oper - FTC_OP_COPY; + + p_cb->req_pending = FALSE; + + if (p_evt->rsp_code == OBX_RSP_OK) + status = BTA_FTC_OK; + + APPL_TRACE_DEBUG2("bta_ftc_obx_action_rsp rsp_code:0x%x, status:%d", p_evt->rsp_code, status); + p_cb->obx_oper = FTC_OP_NONE; + + utl_freebuf((void**)&p_evt->p_pkt); /* Done with Obex packet */ + p_cb->p_cback(event, (tBTA_FTC *)&status); + + /* If successful, initiate a directory listing */ + if (event != BTA_FTC_PERMISSION_EVT && + p_evt->rsp_code == OBX_RSP_OK && p_bta_ft_cfg->auto_file_list && + (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER) ) + { + bta_ftc_get_listing(p_cb, ".", NULL); + } +} + +/******************************************************************************* +** +** Function bta_ftc_obx_get_srm_rsp +** +** Description Process the response to an get command after suspend is sent +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_get_srm_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_ACTION p_act; + /* TODO remove + if (FTC_SUSPEND_REQ_NOT_SENT == p_cb->aborting) + { + p_cb->aborting = 0; + OBX_SessionReq (p_cb->obx_handle, OBX_SESS_OP_SUSPEND, 0); + p_cb->timer_oper = FTC_TIMER_OP_SUSPEND; + bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, p_bta_ft_cfg->suspend_tout ); + } + */ + + if (p_cb->timer_oper == FTC_TIMER_OP_SUSPEND) + { + p_act = bta_ftc_obx_get_rsp; + } + else + p_act = bta_ftc_ignore_obx; + (p_act)(p_cb, p_data); +} + +/******************************************************************************* +** +** Function bta_ftc_ci_write_srm +** +** Description Continue with the current write operation after suspend is sent +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_ci_write_srm(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + if (p_cb->timer_oper == FTC_TIMER_OP_SUSPEND) + { + bta_ftc_ci_write(p_cb, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_ftc_init_putfile +** +** Description Push a file to the OPP or FTP server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_init_putfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FS_CO_STATUS status; + tBTA_FTC data; + BOOLEAN is_dir; + UINT8 rsp_code = OBX_RSP_FAILED; + + data.status = BTA_FTC_FAIL; + if (p_cb->obx_oper == FTC_OP_NONE) + { + if (p_cb->sdp_service != UUID_SERVCLASS_PBAP_PSE) + { + p_cb->obx_oper = FTC_OP_PUT_FILE; + + status = bta_fs_co_access(p_data->api_put.p_name, BTA_FS_ACC_READ, + &is_dir, p_cb->app_id); + /* Verify that the file exists, and get (optional) file length */ + if (is_dir || status != BTA_FS_CO_OK) + { + /* Local file is not accessible or does not exist */ + if (is_dir || status == BTA_FS_CO_EACCES) + rsp_code = OBX_RSP_UNAUTHORIZED; + else + rsp_code = OBX_RSP_NOT_FOUND; + } + else + { + if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_data->api_put.p_name, p_bta_fs_cfg->max_path_len); + p_cb->cout_active = TRUE; + bta_fs_co_open(p_cb->p_name, BTA_FS_O_RDONLY, 0, BTA_FTC_CI_OPEN_EVT, + p_cb->app_id); + rsp_code = OBX_RSP_OK; + } + } + if (rsp_code != OBX_RSP_OK) + { + p_data->obx_evt.rsp_code = rsp_code; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + } + return; + } + else + { + /* PBAP does not allow PUT */ + data.status = BTA_FTC_NO_PERMISSION; + } + } + + p_cb->p_cback(BTA_FTC_PUTFILE_EVT, &data); +} + +/******************************************************************************* +** +** Function bta_ftc_init_getfile +** +** Description Pull a file off the server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_init_getfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_API_GET *p_get = &p_data->api_get; + tBTA_FTC_GET_PARAM *p_param = p_get->p_param; + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTC_STATUS status = BTA_FTC_FAIL; + tBTA_FTC data; + UINT16 buflen; + UINT16 rem_name_len; + BOOLEAN is_ok; + UINT8 *p = (UINT8 *)BTA_FTC_PULL_VCARD_ENTRY_TYPE; + UINT8 *p_start; + UINT16 len = 0; + + /* Available for FTP only */ + if (p_cb->obx_oper == FTC_OP_NONE && + (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER || + p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) ) + { + p_cb->first_req_pkt = TRUE; + p_obx->offset = 0; + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE/*p_cb->peer_mtu*/)) != NULL) + { + /* Add the Name Header to the request */ + is_ok = OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_get->p_rem_name); + + if (p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE && is_ok) + { + /* add type header */ + if (p_get->obj_type == BTA_FTC_GET_PB) + p = (UINT8 *)BTA_FTC_PULL_PB_TYPE; + is_ok = OBX_AddTypeHdr(p_obx->p_pkt, (char *)p); + + /* add app params for PCE */ + p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len); + p = p_start; + if (p_get->obj_type != BTA_FTC_GET_PB || p_param->max_list_count != 0) + { + if (p_param->filter) + { + *p++ = BTA_FTC_APH_FILTER; + *p++ = 8; + /* set proprietary filter to 0 */ + UINT32_TO_BE_STREAM(p, 0); + UINT32_TO_BE_STREAM(p, p_param->filter); + } + if (p_param->format < BTA_FTC_FORMAT_MAX) + { + *p++ = BTA_FTC_APH_FORMAT; + *p++ = 1; + *p++ = p_param->format; + } + } + + if (p_get->obj_type == BTA_FTC_GET_PB) + { + /* this is mandatory */ + *p++ = BTA_FTC_APH_MAX_LIST_COUNT; + *p++ = 2; + UINT16_TO_BE_STREAM(p, p_param->max_list_count); + + if (p_param->list_start_offset) + { + *p++ = BTA_FTC_APH_LIST_STOFF; + *p++ = 2; + UINT16_TO_BE_STREAM(p, p_param->list_start_offset); + } + } + + /* If any of the app param header is added */ + if (p != p_start) + { + OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start)); + } + } + } + + rem_name_len = (UINT16)(strlen(p_get->p_rem_name) + 1); + /* Need a buffer that can hold the local path and UTF-8 filename */ + buflen = p_bta_fs_cfg->max_path_len + 2 + rem_name_len; + + /* Save the UNICODE name of the remote file, and local filename and path */ + if ((p_cb->p_name = (char *)GKI_getbuf(buflen)) != NULL) + { + memset(p_cb->p_name, 0, buflen); + BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len, p_get->p_name, p_bta_fs_cfg->max_path_len-1); + + p_cb->obj_type = p_get->obj_type; + p_cb->obx_oper = FTC_OP_GET_FILE; + if (p_cb->obj_type == BTA_FTC_GET_PB && p_param->max_list_count == 0) + { + /* getting the phone book size only. do not need to open a file */ + bta_ftc_send_get_req(p_cb); + } + else + { + p_cb->cout_active = TRUE; + bta_fs_co_open(p_cb->p_name, + (BTA_FS_O_RDWR | BTA_FS_O_CREAT | BTA_FS_O_TRUNC), + 0, BTA_FTC_CI_OPEN_EVT, p_cb->app_id); + } + status = BTA_FTC_OK; + } + } + + if (status != BTA_FTC_OK) + { + data.status = status; + p_cb->p_cback(BTA_FTC_GETFILE_EVT, &data); + } +} + +/******************************************************************************* +** +** Function bta_ftc_chdir +** +** Description Change Directory and get a listing of it. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_chdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_API_CHDIR *p_chdir = &p_data->api_chdir; + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tOBX_SETPATH_FLAG obx_flags = OBX_SPF_NO_CREATE; + tBTA_FTC_STATUS status = BTA_FTC_FAIL; + UINT16 len = OBX_CMD_POOL_SIZE; /* Don't need special OBX buffer pool */ + + /* Only process if no other OBX operation is active and connected to FTP */ + if (p_cb->obx_oper == FTC_OP_NONE) + { + if (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER || + p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE ) + { + /* Allocate an OBX packet */ + if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, len)) != NULL) + { + status = BTA_FTC_OK; + + /* Add the name header if not backing up */ + if (p_chdir->flag != BTA_FTC_FLAG_BACKUP) + { + if (!OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_chdir->p_dir)) + status = BTA_FTC_FAIL; + } + else + obx_flags |= OBX_SPF_BACKUP; + } + } + } + + if (status == BTA_FTC_OK) + { + if (OBX_SetPathReq(p_cb->obx_handle, obx_flags, p_obx->p_pkt)) + { + status = BTA_FTC_FAIL; + } + else + { + p_cb->req_pending = TRUE; + p_cb->obx_oper = FTC_OP_CHDIR; + p_obx->p_pkt = NULL; /* OBX will free the packet */ + } + + } + + if (status != BTA_FTC_OK) /* Send an error response to the application */ + { + utl_freebuf((void**)&p_obx->p_pkt); + p_cb->p_cback(BTA_FTC_CHDIR_EVT, (tBTA_FTC *)&status); + } +} + +/******************************************************************************* +** +** Function ftp_clnt_listdir +** +** Description List the specified directory contents. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_listdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + /* Only process if no other OBX operation is active and connected to FTP */ + if (p_cb->obx_oper == FTC_OP_NONE) + bta_ftc_get_listing(p_cb, p_data->api_list.p_dir, p_data->api_list.p_param); + else + bta_ftc_listing_err(&p_cb->obx.p_pkt, BTA_FTC_FAIL); +} + +/******************************************************************************* +** +** Function bta_ftc_remove +** Description Remove the specified directory or a file. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_remove(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTC_STATUS status = BTA_FTC_OK; + + APPL_TRACE_DEBUG1("bta_ftc_remove status:%d", p_cb->obx_oper); + + if (p_data->api_mkdir.p_dir[0] != '\0') + { + + /* Only process if no other OBX operation is active and connected to FTP */ + if (p_cb->obx_oper == FTC_OP_NONE) + { + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE)) != NULL) + { + /* Add the Name Header to the request */ + status = BTA_FTC_OK; + OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_remove.p_name); + } + else + status = BTA_FTC_FAIL; + } + else + status = BTA_FTC_BUSY; + } + else + status = BTA_FTC_NOT_FOUND; + + if (status == BTA_FTC_OK) + { + if ((OBX_PutReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS) + { + p_cb->req_pending = TRUE; + p_cb->obx_oper = FTC_OP_DELETE; + p_obx->p_pkt = NULL; /* OBX will free the packet */ + } + else + status = BTA_FTC_FAIL; + } + + if (status != BTA_FTC_OK) /* Send an error response to the application */ + { + utl_freebuf((void**)&p_obx->p_pkt); + p_cb->p_cback(BTA_FTC_REMOVE_EVT, (tBTA_FTC *)&status); + } +} +/******************************************************************************* +** +** Function bta_ftc_mkdir +** +** Description Create the specified directory. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_mkdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTC_STATUS status = BTA_FTC_OK; + + if (p_data->api_mkdir.p_dir[0] != '\0') + { + /* Only process if no other OBX operation is active and connected to FTP */ + if (p_cb->obx_oper == FTC_OP_NONE) + { + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE)) != NULL) + { + /* Add the Name Header to the request */ + status = BTA_FTC_OK; + OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_data->api_mkdir.p_dir); + } + } + else + status = BTA_FTC_BUSY; + } + else + status = BTA_FTC_NOT_FOUND; + + if (status == BTA_FTC_OK ) + { + if ((OBX_SetPathReq(p_cb->obx_handle, 0, p_obx->p_pkt)) == OBX_SUCCESS) + { + p_cb->req_pending = TRUE; + p_cb->obx_oper = FTC_OP_MKDIR; + p_obx->p_pkt = NULL; /* OBX will free the packet */ + } + else + status = BTA_FTC_FAIL; + } + + if (status != BTA_FTC_OK) /* Send an error response to the application */ + { + utl_freebuf((void**)&p_obx->p_pkt); + p_cb->p_cback(BTA_FTC_MKDIR_EVT, (tBTA_FTC *)&status); + } +} + + + +/******************************************************************************* +** +** Function bta_ftc_send_authrsp +** +** Description Pass the response to an authentication request back to the +** client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_send_authrsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + UINT8 *p_pwd = NULL; + UINT8 *p_userid = NULL; + + if (p_bta_ft_cfg->p_bi_action != NULL && + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_AUTHRSP_IDX] && + p_cb->sdp_service == UUID_SERVCLASS_IMAGING_RESPONDER) + { + (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_AUTHRSP_IDX])(p_cb, p_data); + return; + } + else + { + if (p_data->auth_rsp.key_len > 0) + p_pwd = (UINT8 *)p_data->auth_rsp.key; + if (p_data->auth_rsp.userid_len > 0) + p_userid = (UINT8 *)p_data->auth_rsp.userid; + + OBX_AuthResponse(p_cb->obx_handle, p_pwd, p_data->auth_rsp.key_len, + p_userid, p_data->auth_rsp.userid_len, FALSE); + } +} + +/******************************************************************************* +** +** Function bta_ftc_trans_cmpl +** +** Description push/pull complete +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_trans_cmpl(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC param; + + /* Close the opened file */ + if (p_cb->fd >= 0) + { + bta_fs_co_close(p_cb->fd, p_cb->app_id); + p_cb->fd = BTA_FS_INVALID_FD; + } + + param.status = bta_ftc_convert_obx_to_ftc_status(p_data->obx_evt.rsp_code); + + if (p_cb->obx_oper == FTC_OP_PUT_FILE) + p_cb->p_cback(BTA_FTC_PUTFILE_EVT, ¶m); + else if (p_cb->obx_oper == FTC_OP_GET_FILE) + { + if (param.status != BTA_FTC_OK) + { + bta_fs_co_unlink(p_cb->p_name, p_cb->app_id); + APPL_TRACE_WARNING2("FTC: Get File Operation Aborted or Error [%s], status 0x%02x", + p_cb->p_name, param.status); + } + + p_cb->p_cback(BTA_FTC_GETFILE_EVT, ¶m); + } + + /* Clean up control block */ + ftc_reset_cb(p_cb); +} + +/******************************************************************************* +** +** Function bta_ftc_ci_write +** +** Description Continue with the current write operation +** (Get File processing) +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_ci_write(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTC param; + UINT8 rsp_code = OBX_RSP_FAILED; + + p_cb->cout_active = FALSE; + + /* Process write call-in event if operation is still active */ + if (p_cb->obx_oper != FTC_OP_GET_FILE) + return; + + /* Free current packet */ + utl_freebuf((void**)&p_obx->p_pkt); + + /* Process any pending abort */ + if (p_cb->aborting) + { + p_cb->aborting |= FTC_ABORT_COUT_DONE; + + /* If already have response to abort then notify appl and cleanup */ + if (FTC_ABORT_COMPLETED == p_cb->aborting) + { + /* APPL_TRACE_DEBUG0("Received WRITE CALL-IN function; continuing abort..."); */ + + /* OBX_RSP_GONE indicates aborted; used internally when called from API */ + p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + return; + } + } + + if (p_data->write_evt.status == BTA_FS_CO_OK) + { + param.prog.bytes = p_obx->offset; + param.prog.file_size = p_cb->file_size; + p_cb->p_cback(BTA_FTC_PROGRESS_EVT, ¶m); + + /* Send another Get request if not finished */ + if (!p_obx->final_pkt) + { + /* send a new request */ + bta_ftc_send_get_req(p_cb); + rsp_code = OBX_RSP_CONTINUE; + } + else + rsp_code = OBX_RSP_OK; + } + + if (rsp_code != OBX_RSP_CONTINUE) + { + p_data->obx_evt.rsp_code = rsp_code; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ftc_ci_read +** +** Description Handles the response to a read call-out request. +** This is called within the OBX get file request. The +** operation has completed, send the OBX packet out. +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_ci_read(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt; + tBTA_FTC param; + BOOLEAN is_final; + + p_cb->cout_active = FALSE; + + /* Process read call-in event if operation is still active */ + if (p_cb->obx_oper == FTC_OP_PUT_FILE) + { + if (!p_cb->aborting) + { + if (p_revt->status != BTA_FS_CO_OK && p_revt->status != BTA_FS_CO_EOF) + { + p_cb->int_abort = TRUE; + bta_ftc_sm_execute(p_cb, BTA_FTC_API_ABORT_EVT, p_data); + } + else + { + is_final = (p_revt->status == BTA_FS_CO_EOF) ? TRUE: FALSE; + + /* Add the body header to the packet */ + OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_revt->num_read, is_final); + + p_cb->obx.bytes_left -= p_revt->num_read; + p_cb->obx.offset += p_revt->num_read; + + /* Send out the data */ + OBX_PutReq(p_cb->obx_handle, is_final, p_obx->p_pkt); + p_obx->p_pkt = NULL; + p_cb->req_pending = TRUE; + + /* Give application the status */ + param.prog.bytes = p_revt->num_read; + param.prog.file_size = p_cb->file_size; + p_cb->p_cback(BTA_FTC_PROGRESS_EVT, ¶m); + } + } + else + { + /* Process any pending abort */ + p_cb->aborting |= FTC_ABORT_COUT_DONE; + + /* If already have response to abort then notify appl and cleanup */ + if (FTC_ABORT_COMPLETED == p_cb->aborting) + { + /* APPL_TRACE_DEBUG0("Received READ CALL-IN function; continuing abort..."); */ + + /* OBX_RSP_GONE indicates aborted; used internally when called from API */ + p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + return; + } + } + } +} + +/******************************************************************************* +** +** Function bta_ftc_ci_open +** +** Description Continue with the current file open operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_ci_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt; + UINT8 rsp_code = OBX_RSP_FAILED; + + p_cb->cout_active = FALSE; + APPL_TRACE_DEBUG2("bta_ftc_ci_open status:%d, aborting:%d", p_open->status, p_cb->aborting); + + /* Process any pending abort */ + if (p_cb->aborting) + { + p_cb->aborting |= FTC_ABORT_COUT_DONE; + + /* If already have response to abort then notify appl and cleanup */ + if (FTC_ABORT_COMPLETED == p_cb->aborting) + { + /* APPL_TRACE_DEBUG0("Received OPEN CALL-IN function; continuing abort..."); */ + + /* OBX_RSP_GONE indicates aborted; used internally when called from API */ + p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + return; + } + } + + /* if file is accessible read/write the first buffer of data */ + if (p_open->status == BTA_FS_CO_OK) + { + p_cb->fd = p_open->fd; + + /* If using OBEX 1.5 */ + if (p_open->p_file) + { + if ((p_cb->p_name != NULL) || + (p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + /* save the image file name */ + BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_open->p_file, p_bta_fs_cfg->max_path_len); + p_cb->p_name[p_bta_fs_cfg->max_path_len] = '\0'; + p_cb->first_req_pkt = FALSE; + } + } + else + p_cb->first_req_pkt = TRUE; + + APPL_TRACE_DEBUG2("first_req_pkt:%d obx_oper:%d", p_cb->first_req_pkt, p_cb->obx_oper); + + if (p_cb->obx_oper == FTC_OP_PUT_FILE) + { + p_cb->file_size = p_open->file_size; + rsp_code = bta_ftc_cont_put_file(p_cb, p_cb->first_req_pkt); + } + else if (p_cb->obx_oper == FTC_OP_GET_FILE) + { + /* Initiate the first OBX GET request */ + rsp_code = bta_ftc_send_get_req(p_cb); + } + } + else + { + /* If using OBEX 1.5 */ + if (p_open->status == BTA_FS_CO_NONE) + { + rsp_code = OBX_RSP_OK; + if (p_cb->obx_oper == FTC_OP_GET_LIST) + { + bta_ftc_abort(p_cb, NULL); + } + } + else + { + if (p_open->status == BTA_FS_CO_EACCES) + rsp_code = OBX_RSP_UNAUTHORIZED; + else /* File could not be found */ + rsp_code = OBX_RSP_NOT_FOUND; + } + } + + if (rsp_code != OBX_RSP_OK) + { + p_data->obx_evt.rsp_code = rsp_code; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ftc_ci_resume +** +** Description Continue with the resume session +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_ci_resume(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FS_CI_RESUME_EVT *p_resume = &p_data->resume_evt; + + APPL_TRACE_DEBUG3("bta_ftc_ci_resume status:%d, ssn:%d, info:%d", + p_resume->status, p_resume->ssn, p_resume->info); + + if (p_resume->status == BTA_FS_CO_OK && + OBX_AllocSession (p_resume->p_sess_info, 0, &p_cb->psm, + bta_ftc_obx_cback, &p_cb->obx_handle) == OBX_SUCCESS) + { + BTM_SetSecurityLevel (TRUE, "BTA_FTC", BTM_SEC_SERVICE_OBEX_FTP, + p_cb->sec_mask, p_cb->psm, + 0, 0); + OBX_ResumeSession (p_cb->bd_addr, p_resume->ssn, p_resume->offset, p_cb->obx_handle); + } + else + { + p_cb->status = BTA_FTC_OBX_ERR; + p_data->obx_evt.rsp_code = OBX_RSP_FAILED; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CLOSE_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ftc_obx_conn_rsp +** +** Description Process the OBX connect event. +** If FTP service, get directory listing. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_conn_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_FTC param; + tOBX_SESS_EVT *p_sess; + UINT8 obx_oper, *p_obx_oper = &p_cb->obx_oper; + + APPL_TRACE_DEBUG1("bta_ftc_obx_conn_rsp obx_event=%d", p_evt->obx_event); + + /* If using OBEX 1.5 */ + if (p_evt->obx_event == OBX_SESSION_RSP_EVT) + { + p_sess = &p_evt->param.sess; + APPL_TRACE_DEBUG2("bta_ftc_obx_conn_rsp sess_id:0x%x/0x%x", p_cb->p_sess_info, p_sess->p_sess_info); + p_cb->p_sess_info = p_sess->p_sess_info; + APPL_TRACE_DEBUG2("client cb p_sess_info:0x%x obj_offset:x%x", p_cb->p_sess_info, p_sess->obj_offset); + if (p_cb->nonce != BTA_FTC_RESUME_NONCE) + { + p_obx_oper = &obx_oper; + p_cb->obx_oper = FTC_OP_NONE; + } + bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, p_sess->ssn, BTA_FS_CO_SESS_ST_ACTIVE, NULL, p_obx_oper, p_cb->app_id); + if ((p_sess->sess_op == OBX_SESS_OP_CREATE) || (p_sess->sess_op == OBX_SESS_OP_RESUME)) + { + p_cb->state = BTA_FTC_W4_CONN_ST; + } + if (p_cb->obx_oper) + bta_fs_co_resume_op(p_sess->obj_offset, BTA_FTC_CI_OPEN_EVT, p_cb->app_id); + return; + } + + p_cb->peer_mtu = p_data->obx_evt.param.conn.mtu; + + APPL_TRACE_DEBUG2("bta_ftc_obx_conn_rsp peer_mtu=%d obx_oper:0x%x", p_cb->peer_mtu, p_cb->obx_oper); + + /* OPP is connected and ready */ + if (p_cb->sdp_service == UUID_SERVCLASS_OBEX_OBJECT_PUSH) + { + param.open.service = BTA_OPP_SERVICE_ID; + APPL_TRACE_EVENT0("[BTA FTC]OPP Service Id "); + } + /* PBAP is connected and ready */ + else if (p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) + { + param.open.service = BTA_PBAP_SERVICE_ID; + APPL_TRACE_EVENT0("[BTA FTC]PBAP Service Id "); + } + else /* Initiate directory listing if FTP service */ + { + APPL_TRACE_EVENT0("[BTA FTC]FTP Service Id "); + param.open.service = BTA_FTP_SERVICE_ID; + if (p_bta_ft_cfg->auto_file_list && !p_cb->obx_oper) + { + bta_ftc_get_listing(p_cb, ".", NULL); + } + } + + if (p_cb->p_sess_info == NULL) + { + bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id); + } + p_cb->suspending = FALSE; + + /* inform role manager */ + bta_sys_conn_open( BTA_ID_FTC ,p_cb->app_id, p_cb->bd_addr); + + param.open.version = p_cb->version; + p_cb->p_cback(BTA_FTC_OPEN_EVT, ¶m); + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/******************************************************************************* +** +** Function bta_ftc_obx_sess_rsp +** +** Description Process the OBX session event. +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_sess_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess; + + APPL_TRACE_DEBUG3("bta_ftc_obx_sess_rsp obx_event=%d sess_op:%d, ssn:%d", + p_evt->obx_event, p_sess->sess_op, p_sess->ssn); + if (p_evt->obx_event == OBX_SESSION_RSP_EVT && p_sess->sess_op == OBX_SESS_OP_SUSPEND) + { + p_cb->p_sess_info = p_sess->p_sess_info; + APPL_TRACE_DEBUG1("client cb p_sess_info:0x%x", p_cb->p_sess_info); + bta_fs_co_suspend(p_cb->bd_addr, p_cb->p_sess_info, p_sess->ssn, &p_sess->timeout, NULL, p_cb->obx_oper, p_cb->app_id); + } +} + +/******************************************************************************* +** +** Function bta_ftc_suspended +** +** Description Process transport down suspend. +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_suspended(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess; + UINT32 offset = 0; + + APPL_TRACE_DEBUG4("bta_ftc_suspended obx_event=%d sess_op:%d, ssn:%d, obx_oper:%d", + p_evt->obx_event, p_sess->sess_op, p_sess->ssn, p_cb->obx_oper); + if (p_evt->obx_event == OBX_SESSION_INFO_EVT) + { + if ((p_cb->obx_oper != FTC_OP_GET_FILE) && (p_cb->obx_oper != FTC_OP_PUT_FILE) && (p_cb->obx_oper != FTC_OP_GET_LIST)) + { + /* the other obx ops are single transaction. + * If the link is dropped before the transaction ends, re-transmit the request when the session resumes */ + p_sess->ssn--; + p_cb->obx_oper = FTC_OP_NONE; + } + p_cb->suspending = TRUE; + bta_fs_co_suspend(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn, + &p_sess->timeout, &offset, p_cb->obx_oper, p_cb->app_id); + /* do not need to worry about active call-out here. + * this is a result of OBX_SESSION_INFO_EVT + * OBX would report OBX_CLOSE_IND_EVT, which will eventually call bta_ftc_close_complete */ + } +} + +/******************************************************************************* +** +** Function bta_ftc_obx_abort_rsp +** +** Description Process the OBX abort event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_abort_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + bta_sys_stop_timer(&p_cb->rsp_timer); + + /* Done with Obex packet */ + utl_freebuf((void**)&p_data->obx_evt.p_pkt); + + if (p_cb->obx_oper != FTC_OP_NONE) + { + if (!p_cb->cout_active) + { + /* OBX_RSP_GONE indicates aborted; used internally when called from API */ + p_data->obx_evt.rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + } + else /* must wait for cout function to complete before finishing the abort */ + { + /* Mark the fact we have already received the response from the peer */ + p_cb->aborting |= FTC_ABORT_RSP_RCVD; + /* APPL_TRACE_DEBUG1("ftc_obx_abort_rsp()->Rcvd abort_rsp; waiting for callin...", + p_cb->aborting); */ + } + } +} + +/******************************************************************************* +** +** Function bta_ftc_obx_password +** +** Description Process the OBX password request +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_password(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_FTC_AUTH parms; + tOBX_AUTH_OPT options; + + memset(&parms, 0, sizeof(tBTA_FTC_AUTH)); + + /* Extract user id from packet (if available) */ + if (OBX_ReadChallenge(p_evt->p_pkt, &parms.realm_charset, + &parms.p_realm, + &parms.realm_len, &options)) + { + if (options & OBX_AO_USR_ID) + parms.userid_required = TRUE; + } + + /* Don't need OBX packet any longer */ + utl_freebuf((void**)&p_evt->p_pkt); + + /* Notify application */ + p_cb->p_cback(BTA_FTC_AUTH_EVT, (tBTA_FTC *)&parms); +} + +/******************************************************************************* +** +** Function bta_ftc_obx_timeout +** +** Description Process the OBX timeout event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + utl_freebuf((void**)&p_data->obx_evt.p_pkt); + + /* If currently processing OBX request, peer is unresponsive so we're done */ + if (p_cb->aborting || p_cb->obx_oper != FTC_OP_NONE) + { +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + if (p_cb->bic_handle != BTA_BIC_INVALID_HANDLE) + { + BTA_BicDeRegister(p_cb->bic_handle); + p_cb->bic_handle = BTA_BIC_INVALID_HANDLE; + } + else +#endif + { + p_data->obx_evt.rsp_code = OBX_RSP_GONE; + p_cb->status = BTA_FTC_OBX_TOUT; + + /* Start stop response timer */ + p_cb->timer_oper = FTC_TIMER_OP_STOP; + bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, + p_bta_ft_cfg->stop_tout); + + OBX_DisconnectReq(p_cb->obx_handle, NULL); + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CLOSE_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_ftc_obx_put_rsp +** +** Description Process the OBX file put and delete file/folder events +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_put_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_FTC_STATUS status; + + p_cb->req_pending = FALSE; + p_cb->first_req_pkt = FALSE; + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); + + if (p_cb->obx_oper == FTC_OP_PUT_FILE) + { + /* If not finished with Put, start another read */ + if (p_evt->rsp_code == OBX_RSP_CONTINUE) + bta_ftc_cont_put_file(p_cb, FALSE); + else + { + p_data->obx_evt.rsp_code = p_evt->rsp_code; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + } + } + + else if (p_cb->obx_oper == FTC_OP_DELETE) + { + status = bta_ftc_convert_obx_to_ftc_status(p_data->obx_evt.rsp_code); + p_cb->obx_oper = FTC_OP_NONE; + p_cb->p_cback(BTA_FTC_REMOVE_EVT, (tBTA_FTC *)&status); + } + +} + +/******************************************************************************* +** +** Function bta_ftc_obx_get_rsp +** +** Description Process the OBX file get and folder listing events +** If the type header is not folder listing, then pulling a file. +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + + APPL_TRACE_DEBUG2("bta_ftc_obx_get_rsp req_pending=%d obx_oper:%d", p_cb->req_pending, p_cb->obx_oper); + p_cb->req_pending = FALSE; + + if (p_cb->obx_oper == FTC_OP_GET_FILE) + bta_ftc_proc_get_rsp(p_cb, p_data); + else if (p_cb->obx_oper == FTC_OP_GET_LIST) + bta_ftc_proc_list_data(p_cb, p_evt); + else /* Release the unexpected OBX response packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/******************************************************************************* +** +** Function bta_ftc_obx_setpath_rsp +** +** Description Process the response to a change or make directory requests +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_setpath_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_FTC_STATUS status = BTA_FTC_FAIL; + tBTA_FTC_EVT event = BTA_FTC_CHDIR_EVT; + + p_cb->req_pending = FALSE; + + if (p_cb->obx_oper == FTC_OP_MKDIR) + event = BTA_FTC_MKDIR_EVT; + + if (p_evt->rsp_code == OBX_RSP_OK) + status = BTA_FTC_OK; + + p_cb->obx_oper = FTC_OP_NONE; + + utl_freebuf((void**)&p_evt->p_pkt); /* Done with Obex packet */ + p_cb->p_cback(event, (tBTA_FTC *)&status); + + /* If successful, initiate a directory listing */ + if (p_evt->rsp_code == OBX_RSP_OK && p_bta_ft_cfg->auto_file_list && + (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER)) + { + bta_ftc_get_listing(p_cb, ".", NULL); + } +} + +/******************************************************************************* +** +** Function bta_ftc_rsp_timeout +** +** Description Process the OBX response timeout event +** stop and abort +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_rsp_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + p_cb->timer_oper = FTC_TIMER_OP_STOP; + if (p_cb->timer_oper == FTC_TIMER_OP_ABORT) + { + /* Start stop response timer */ + p_cb->status = BTA_FTC_ABORTED; + bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, + p_bta_ft_cfg->stop_tout); + + OBX_DisconnectReq(p_cb->obx_handle, NULL); + } + else /* Timeout waiting for disconnect response */ + { + p_cb->cout_active = FALSE; + bta_ftc_initialize(p_cb, p_data); +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + BTA_BicFreeXmlData(BTA_BIC_CAPABILITIES_EVT, (tBTA_BI_XML **)&p_cb->p_caps); +#endif + /* force OBX to close port */ + OBX_DisconnectReq(p_cb->obx_handle, NULL); + } +} + +/******************************************************************************* +** +** Function bta_ftc_initialize +** +** Description Initialize the control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_initialize(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FS_CO_STATUS status; + + bta_sys_stop_timer(&p_cb->rsp_timer); + + /* Close any open files */ + if (p_cb->fd >= 0) + { + bta_fs_co_close(p_cb->fd, p_cb->app_id); + p_cb->fd = BTA_FS_INVALID_FD; + + /* Delete an aborted unfinished get file operation */ + if (p_cb->obx_oper == FTC_OP_GET_FILE && p_cb->suspending == FALSE) + { + status = bta_fs_co_unlink(p_cb->p_name, p_cb->app_id); + APPL_TRACE_WARNING2("FTC: Remove ABORTED Get File Operation [%s], status 0x%02x", + p_cb->p_name, status); + } + } + + /* Clean up control block */ + ftc_reset_cb(p_cb); + p_cb->sdp_service = 0; + p_cb->sdp_pending = FALSE; + p_cb->suspending = FALSE; + p_cb->p_sess_info = NULL; + + if (p_cb->disabling) + { + if (p_cb->sdp_handle) + { + SDP_DeleteRecord(p_cb->sdp_handle); + p_cb->sdp_handle = 0; + bta_sys_remove_uuid( UUID_SERVCLASS_PBAP_PCE ); + } + p_cb->is_enabled = FALSE; + p_cb->disabling = FALSE; + bta_ftc_sm_execute(p_cb, BTA_FTC_DISABLE_CMPL_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_ftc_stop_client +** +** Description Stop OBX client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_stop_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + INT32 timeout; + + APPL_TRACE_DEBUG1("bta_ftc_stop_client suspend:%d", p_data->api_close.suspend); +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + if (p_bta_ft_cfg->p_bi_action && + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_DEREGISTER_IDX] && + p_cb->bic_handle != BTA_BIC_INVALID_HANDLE) + { + (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_DEREGISTER_IDX])(p_cb, p_data); + } + else if (!p_cb->sdp_pending) +#else + if (!p_cb->sdp_pending) +#endif + { + if (p_data->api_close.suspend) + { + timeout = p_bta_ft_cfg->suspend_tout; + p_cb->timer_oper = FTC_TIMER_OP_SUSPEND; + p_cb->suspending = TRUE; + OBX_SessionReq (p_cb->obx_handle, OBX_SESS_OP_SUSPEND, 0); + p_cb->state = BTA_FTC_SUSPENDING_ST; + + } + else + { + bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id); + + timeout = p_bta_ft_cfg->stop_tout; + p_cb->timer_oper = FTC_TIMER_OP_STOP; + OBX_DisconnectReq(p_cb->obx_handle, NULL); + } + /* Start stop response timer */ + bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, timeout ); + } +} + +/******************************************************************************* +** +** Function bta_ftc_close +** +** Description If not waiting for a call-in function, complete the closing +** of the channel. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_close(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + /* finished if not waiting on a call-in function */ + if (!p_cb->sdp_pending && !p_cb->cout_active) + bta_ftc_sm_execute(p_cb, BTA_FTC_CLOSE_CMPL_EVT, p_data); +} + +/******************************************************************************* +** +** Function bta_ftc_close +** +** Description If not waiting for a call-in function, complete the closing +** of the channel. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_open_fail(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + bta_ftc_close(p_cb, p_data); +} + +/******************************************************************************* +** +** Function bta_ftc_start_client +** +** Description Start an FTP or OPP client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_start_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tOBX_STATUS status; + UINT16 mtu = OBX_MAX_MTU; + BOOLEAN srm = p_cb->srm; + UINT32 nonce = p_cb->nonce; + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + + p_cb->status = BTA_FTC_OK; + p_cb->p_sess_info = NULL; + + if ( p_bta_ft_cfg->p_bi_action && + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_REGISTER_IDX] && + p_cb->sdp_service == UUID_SERVCLASS_IMAGING_RESPONDER) + { + (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_REGISTER_IDX])(p_cb, p_data); + return; + } + + /* If using OBEX 1.5 */ + if (p_cb->nonce == BTA_FTC_RESUME_NONCE) + { + APPL_TRACE_DEBUG1("bta_ftc_start_client psm:0x%x", p_data->sdp_ok.psm); + p_cb->psm = p_data->sdp_ok.psm; + bta_fs_co_resume (BTA_FTC_CI_SESSION_EVT, p_cb->app_id); + } + /* Allocate an OBX packet */ + else + { + if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(OBX_HANDLE_NULL, OBX_CMD_POOL_SIZE)) != NULL) + { + p_cb->version = p_data->sdp_ok.version; + + /* Add the target header if connecting to FTP service */ + if (p_cb->sdp_service == UUID_SERVCLASS_OBEX_FILE_TRANSFER) + { + OBX_AddTargetHdr(p_obx->p_pkt, (UINT8 *)BTA_FTC_FOLDER_BROWSING_TARGET_UUID, + BTA_FTC_UUID_LENGTH); + } + /* Add the target header if connecting to PBAP service */ + else if (p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) + { + OBX_AddTargetHdr(p_obx->p_pkt, (UINT8 *)BTA_FTC_PB_ACCESS_TARGET_UUID, + BTA_FTC_UUID_LENGTH); + } + + status = OBX_AllocSession (NULL, p_data->sdp_ok.scn, &p_data->sdp_ok.psm, + bta_ftc_obx_cback, &p_cb->obx_handle); + + /* set security level */ + if (p_data->sdp_ok.scn) + { + BTM_SetSecurityLevel (TRUE, "BTA_FTC", BTM_SEC_SERVICE_OBEX_FTP, + p_cb->sec_mask, BT_PSM_RFCOMM, + BTM_SEC_PROTO_RFCOMM, p_data->sdp_ok.scn); + srm = 0; + nonce = 0; + } + else + { + BTM_SetSecurityLevel (TRUE, "BTA_FTC", BTM_SEC_SERVICE_OBEX_FTP, + p_cb->sec_mask, p_data->sdp_ok.psm, 0, 0); + } + + if (status == OBX_SUCCESS) + { + OBX_CreateSession (p_cb->bd_addr, mtu, srm, nonce, + p_cb->obx_handle, p_obx->p_pkt); + p_obx->p_pkt = NULL; /* OBX will free the memory */ + return; + } + /* else stay in this function to report failure */ + return; + } + else + { + p_cb->status = BTA_FTC_OBX_ERR; + p_data->obx_evt.rsp_code = OBX_RSP_FAILED; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CLOSE_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_ftc_free_db +** +** Description Free buffer used for service discovery database. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_free_db(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + utl_freebuf((void**)&p_cb->p_db); + p_cb->sdp_pending = FALSE; +} + +/******************************************************************************* +** +** Function bta_ftc_ignore_obx +** +** Description Free OBX packet for ignored OBX events. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_ignore_obx(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + utl_freebuf((void**)&p_data->obx_evt.p_pkt); +} + +/******************************************************************************* +** +** Function bta_ftc_find_service +** +** Description Perform service discovery to find OPP and/or FTP services on +** peer device. If the service ID is both FTP and OPP then FTP +** is tried first. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_find_service(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tSDP_UUID uuid_list; + UINT16 attr_list[5]; + UINT16 num_attrs = 4; + tBTA_SERVICE_MASK ftc_services = (BTA_FTP_SERVICE_MASK | BTA_OPP_SERVICE_MASK + | BTA_BIP_SERVICE_MASK | BTA_PBAP_SERVICE_MASK); + + APPL_TRACE_DEBUG1("bta_ftc_find_service event:0x%x", BTA_FTC_API_OPEN_EVT); + + /* Make sure at least one service was specified */ + if (p_cb->services & ftc_services) + { + if ((p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_FTC_DISC_SIZE)) != NULL) + { + p_cb->status = BTA_FTC_OK; + + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[3] = ATTR_ID_OBX_OVR_L2CAP_PSM; + + uuid_list.len = LEN_UUID_16; + + /* Try FTP if its service is desired */ + if (p_cb->services & BTA_FTP_SERVICE_MASK) + { + p_cb->services &= ~BTA_FTP_SERVICE_MASK; + p_cb->sdp_service = UUID_SERVCLASS_OBEX_FILE_TRANSFER; + uuid_list.uu.uuid16 = UUID_SERVCLASS_OBEX_FILE_TRANSFER; + } + else if (p_cb->services & BTA_PBAP_SERVICE_MASK) + { + p_cb->services &= ~BTA_PBAP_SERVICE_MASK; + p_cb->sdp_service = UUID_SERVCLASS_PBAP_PSE; + uuid_list.uu.uuid16 = UUID_SERVCLASS_PBAP_PSE; + } + else if (p_cb->services & BTA_OPP_SERVICE_MASK) + { + p_cb->services &= ~BTA_OPP_SERVICE_MASK; + p_cb->sdp_service = UUID_SERVCLASS_OBEX_OBJECT_PUSH; + uuid_list.uu.uuid16 = UUID_SERVCLASS_OBEX_OBJECT_PUSH; + } + else if (p_bta_ft_cfg->p_bi_action) + { + /* Try the basic imaging service */ + p_cb->services &= ~BTA_BIP_SERVICE_MASK; + p_cb->sdp_service = UUID_SERVCLASS_IMAGING_RESPONDER; + uuid_list.uu.uuid16 = UUID_SERVCLASS_IMAGING_RESPONDER; + attr_list[num_attrs++] = ATTR_ID_SUPPORTED_FEATURES; + } + + SDP_InitDiscoveryDb(p_cb->p_db, BTA_FTC_DISC_SIZE, 1, &uuid_list, num_attrs, attr_list); + if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, bta_ftc_sdp_cback)) + { + p_cb->status = BTA_FTC_SDP_ERR; + bta_ftc_sm_execute(p_cb, BTA_FTC_SDP_FAIL_EVT, p_data); + + } + + p_cb->sdp_pending = TRUE; + } + } + else /* No services available */ + { + p_cb->status = BTA_FTC_SERVICE_UNAVL; + bta_ftc_sm_execute(p_cb, BTA_FTC_SDP_FAIL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ftc_close_complete +** +** Description Finishes the memory cleanup after a channel is closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_close_complete(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC param; + + param.status = p_cb->status; + p_cb->cout_active = FALSE; + bta_ftc_initialize(p_cb, p_data); + + if (p_bta_ft_cfg->p_bi_action && p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_FREEXML_IDX]) + (p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_FREEXML_IDX])(p_cb, p_data); + + /* inform role manager */ + bta_sys_conn_close( BTA_ID_FTC ,p_cb->app_id, p_cb->bd_addr); + bta_fs_co_session_info(p_cb->bd_addr, p_cb->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id); + + p_cb->p_cback(BTA_FTC_CLOSE_EVT, ¶m); +} + +/******************************************************************************* +** +** Function bta_ftc_set_disable +** +** Description Finishes the memory cleanup after a channel is closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_set_disable(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + p_cb->disabling = TRUE; +} + +/******************************************************************************* +** +** Function bta_ftc_bic_put +** +** Description Initiate a connection with a peer device's service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_bic_put(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + if (p_bta_ft_cfg->p_bi_action && + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_PUT_IDX]) + { + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_PUT_IDX](p_cb, p_data); + } + return; +} + +/******************************************************************************* +** +** Function bta_ftc_bic_abort +** +** Description Initiate a connection with a peer device's service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_bic_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + if (p_bta_ft_cfg->p_bi_action && + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_ABORT_IDX]) + { + p_bta_ft_cfg->p_bi_action[BTA_FTC_BI_ABORT_IDX](p_cb, p_data); + } + return; +} + +/***************************************************************************** +** Callback Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_ftc_obx_cback +** +** Description OBX callback function. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, UINT8 rsp_code, + tOBX_EVT_PARAM param, BT_HDR *p_pkt) +{ + tBTA_FTC_OBX_EVT *p_obx_msg; + UINT16 event = 0; + UINT16 size = sizeof(tBTA_FTC_OBX_EVT); + +#if BTA_FTC_DEBUG == TRUE + APPL_TRACE_DEBUG2("OBX Event Callback: obx_event [%s] 0x%x", ftc_obx_evt_code(obx_event), p_pkt); +#endif + + switch (obx_event) + { + case OBX_SESSION_INFO_EVT: + size += OBX_SESSION_INFO_SIZE; + /* Falls through */ + + case OBX_SESSION_RSP_EVT: + case OBX_CONNECT_RSP_EVT: + if (rsp_code == OBX_RSP_OK) + { + event = BTA_FTC_OBX_CONN_RSP_EVT; + } + else /* Obex will disconnect underneath BTA */ + { + APPL_TRACE_WARNING1("FTC_CBACK: Bad connect response 0x%02x", rsp_code); + if (p_pkt) + GKI_freebuf(p_pkt); + return; + } + break; + + case OBX_ACTION_RSP_EVT: + event = BTA_FTC_OBX_ACTION_RSP_EVT; + break; + + case OBX_PUT_RSP_EVT: + event = BTA_FTC_OBX_PUT_RSP_EVT; + break; + case OBX_GET_RSP_EVT: + event = BTA_FTC_OBX_GET_RSP_EVT; + break; + case OBX_SETPATH_RSP_EVT: + event = BTA_FTC_OBX_SETPATH_RSP_EVT; + break; + case OBX_ABORT_RSP_EVT: + event = BTA_FTC_OBX_ABORT_RSP_EVT; + break; + case OBX_CLOSE_IND_EVT: + event = BTA_FTC_OBX_CLOSE_EVT; + break; + case OBX_TIMEOUT_EVT: + event = BTA_FTC_OBX_TOUT_EVT; + break; + case OBX_PASSWORD_EVT: + event = BTA_FTC_OBX_PASSWORD_EVT; + break; + + default: + /* case OBX_DISCONNECT_RSP_EVT: Handled when OBX_CLOSE_IND_EVT arrives */ + if (p_pkt) + GKI_freebuf(p_pkt); + return; + + } + + /* send event to BTA, if any */ + if ((p_obx_msg = (tBTA_FTC_OBX_EVT *) GKI_getbuf(size)) != NULL) + { + APPL_TRACE_DEBUG2("obx_event [%d] event:0x%x", obx_event, event); + p_obx_msg->hdr.event = event; + p_obx_msg->obx_event = obx_event; + p_obx_msg->handle = handle; + p_obx_msg->rsp_code = rsp_code; + p_obx_msg->param = param; + p_obx_msg->p_pkt = p_pkt; + + if (obx_event == OBX_SESSION_INFO_EVT) + { + p_obx_msg->param.sess.p_sess_info = (UINT8 *)(p_obx_msg + 1); + memcpy (p_obx_msg->param.sess.p_sess_info, param.sess.p_sess_info, OBX_SESSION_INFO_SIZE); + } + + bta_sys_sendmsg(p_obx_msg); + } +} + + +/****************************************************************************** +** +** Function bta_ftc_sdp_cback +** +** Description This is the SDP callback function used by FTC. +** This function will be executed by SDP when the service +** search is completed. If the search is successful, it +** finds the first record in the database that matches the +** UUID of the search. Then retrieves the scn from the +** record. +** +** Returns Nothing. +** +******************************************************************************/ +static void bta_ftc_sdp_cback(UINT16 status) +{ + tBTA_FTC_CB *p_cb = &bta_ftc_cb; + tBTA_FTC_SDP_OK_EVT *p_buf; + tSDP_DISC_REC *p_rec = NULL; + tSDP_PROTOCOL_ELEM pe; + UINT8 scn = 0; + UINT16 psm = 0; + UINT16 version = GOEP_LEGACY_VERSION; + BOOLEAN found = FALSE; + tSDP_DISC_ATTR *p_attr; +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + tBIP_FEATURE_FLAGS features = 0; +#endif + + APPL_TRACE_DEBUG1("bta_ftc_sdp_cback status:%d", status); + + if ( (status == SDP_SUCCESS) || (status == SDP_DB_FULL) ) + { + status = SDP_SUCCESS; + /* loop through all records we found */ + do + { + /* get next record; if none found, we're done */ + if ((p_rec = SDP_FindServiceInDb(p_cb->p_db, p_cb->sdp_service, + p_rec)) == NULL) + break; + + /* this is an optional attribute */ + SDP_FindProfileVersionInRec (p_rec, p_cb->sdp_service, &version); + + /* get psm from proto desc list alternative; if not found, go to next record */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, + ATTR_ID_OBX_OVR_L2CAP_PSM)) != NULL) + { + psm = p_attr->attr_value.v.u16; + APPL_TRACE_DEBUG1("attr_len_type: x%x", p_attr->attr_len_type); + if ((SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) && L2C_IS_VALID_PSM(psm)) + { + found = TRUE; + if (version == GOEP_LEGACY_VERSION) + { + APPL_TRACE_ERROR0("Lacking mandatory attribute/version"); + version = BTA_FT_ENHANCED_VERSION; + } + break; + } + } + + if (!found) + { + /* get scn from proto desc list; if not found, go to next record */ + if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) + { + if ( p_bta_ft_cfg->p_bi_action && p_cb->sdp_service == UUID_SERVCLASS_IMAGING_RESPONDER) + { + /* Check if the Push feature is supported */ +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) + { + features = p_attr->attr_value.v.u16; + APPL_TRACE_DEBUG1("supported BIP features: x%x", features); + if (features & BIP_FT_IMG_PUSH_FLAGS) + { + found = TRUE; + } + } +#endif + } + else + { + found = TRUE; + } + scn = (UINT8) pe.params[0]; + + /* we've got everything, we're done */ + break; + } + else + { + continue; + } + } + } while (TRUE); + } + + APPL_TRACE_DEBUG4("found: %d scn:%d, psm:0x%x version:0x%x",found , scn, psm, version); + + /* send result in event back to BTA */ + if ((p_buf = (tBTA_FTC_SDP_OK_EVT *) GKI_getbuf(sizeof(tBTA_FTC_SDP_OK_EVT))) != NULL) + { + p_buf->hdr.event = BTA_FTC_SDP_FAIL_EVT; + p_cb->status = BTA_FTC_SERVICE_UNAVL; + + if (status == SDP_SUCCESS) + { + if (found == TRUE) + { + p_buf->hdr.event = BTA_FTC_SDP_OK_EVT; + p_buf->scn = scn; + p_buf->psm = psm; + p_buf->version = version; + } + /* See if OPP service needs to be searched for */ + else if (p_cb->services & (BTA_OPP_SERVICE_MASK|BTA_BIP_SERVICE_MASK)) + { + p_buf->hdr.event = BTA_FTC_SDP_NEXT_EVT; + } + } + + bta_sys_sendmsg(p_buf); + } +} + +/***************************************************************************** +** Local FTP Event Processing Functions +*****************************************************************************/ +static void ftc_reset_cb (tBTA_FTC_CB *p_cb) +{ + /* Clean up control block */ + utl_freebuf((void**)&p_cb->obx.p_pkt); + utl_freebuf((void**)(BT_HDR **)&p_cb->p_name); + p_cb->obx_oper = FTC_OP_NONE; + p_cb->aborting = 0; + p_cb->int_abort = FALSE; + p_cb->req_pending = FALSE; +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_FTC_DEBUG == TRUE + +/******************************************************************************* +** +** Function ftc_obx_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *ftc_obx_evt_code(tOBX_EVENT evt_code) +{ + switch (evt_code) + { + case OBX_CONNECT_RSP_EVT: + return "OBX_CONNECT_RSP_EVT"; + case OBX_DISCONNECT_RSP_EVT: + return "OBX_DISCONNECT_RSP_EVT"; + case OBX_PUT_RSP_EVT: + return "OBX_PUT_RSP_EVT"; + case OBX_GET_RSP_EVT: + return "OBX_GET_RSP_EVT"; + case OBX_SETPATH_RSP_EVT: + return "OBX_SETPATH_RSP_EVT"; + case OBX_ABORT_RSP_EVT: + return "OBX_ABORT_RSP_EVT"; + case OBX_CLOSE_IND_EVT: + return "OBX_CLOSE_IND_EVT"; + case OBX_TIMEOUT_EVT: + return "OBX_TIMEOUT_EVT"; + case OBX_PASSWORD_EVT: + return "OBX_PASSWORD_EVT"; + case OBX_SESSION_RSP_EVT: + return "OBX_SESSION_RSP_EVT"; + case OBX_ACTION_RSP_EVT: + return "OBX_ACTION_RSP_EVT"; + case OBX_SESSION_INFO_EVT: + return "OBX_SESSION_INFO_EVT"; + default: + return "unknown OBX event code"; + } +} +#endif /* Debug Functions */ +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_ftc_api.c b/bta/ft/bta_ftc_api.c new file mode 100644 index 0000000..31722cf --- /dev/null +++ b/bta/ft/bta_ftc_api.c @@ -0,0 +1,796 @@ +/***************************************************************************** +** +** Name: bta_ftc_api.c +** +** Description: This is the implementation of the API for the file +** transfer server subsystem of BTA, Widcomm's Bluetooth +** application layer for mobile phones. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#include "bt_target.h" + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_fs_api.h" +#include "bta_ftc_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +static const tBTA_SYS_REG bta_ftc_reg = +{ + bta_ftc_hdl_event, + BTA_FtcDisable +}; + +/******************************************************************************* +** +** Function BTA_FtcEnable +** +** Description Enable the file transfer client. This function must be +** called before any other functions in the FTC API are called. +** When the enable operation is complete the callback function +** will be called with an BTA_FTC_ENABLE_EVT event. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcEnable(tBTA_FTC_CBACK *p_cback, UINT8 app_id) +{ + tBTA_FTC_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_FTC, &bta_ftc_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_FTC_API_ENABLE *)GKI_getbuf(sizeof(tBTA_FTC_API_ENABLE))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_FTC_API_ENABLE)); + + p_buf->hdr.event = BTA_FTC_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->app_id = app_id; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcDisable +** +** Description Disable the file transfer client. If the client is currently +** connected to a peer device the connection will be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_FTC); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_FTC_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcOpen +** +** Description Open a connection to an FTP, PBAP, OPP or BIP server. +** If parameter services is set to use both all services, +** the client will attempt to connect to the device using +** FTP first and then PBAP, OPP, BIP. +** When the connection is open the callback function +** will be called with a BTA_FTC_OPEN_EVT. If the connection +** fails or otherwise is closed the callback function will be +** called with a BTA_FTC_CLOSE_EVT. +** +** If the connection is opened with FTP profile and +** bta_ft_cfg.auto_file_list is TRUE , the callback +** function will be called with one or more BTA_FTC_LIST_EVT +** containing directory list information formatted in XML as +** described in the IrOBEX Spec, Version 1.2, section 9.1.2.3. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services, + BOOLEAN srm, UINT32 nonce) +{ + tBTA_FTC_API_OPEN *p_buf; + + if ((p_buf = (tBTA_FTC_API_OPEN *)GKI_getbuf(sizeof(tBTA_FTC_API_OPEN))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_FTC_API_OPEN)); + + p_buf->hdr.event = BTA_FTC_API_OPEN_EVT; + p_buf->services = services; + p_buf->sec_mask = sec_mask; + p_buf->srm = srm; + p_buf->nonce = nonce; + memcpy(p_buf->bd_addr, bd_addr, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcSuspend +** +** Description Suspend the current connection to the server. +** This is allowed only for the sessions created by +** BTA_FtcConnect with nonce!=0 +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcSuspend(void) +{ + tBTA_FTC_API_CLOSE *p_buf; + + APPL_TRACE_DEBUG0("BTA_FtcSuspend"); + if ((p_buf = (tBTA_FTC_API_CLOSE *)GKI_getbuf(sizeof(tBTA_FTC_API_CLOSE))) != NULL) + { + p_buf->hdr.event = BTA_FTC_API_CLOSE_EVT; + p_buf->suspend = TRUE; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcClose +** +** Description Close the current connection to the server. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcClose(void) +{ + tBTA_FTC_API_CLOSE *p_buf; + + if ((p_buf = (tBTA_FTC_API_CLOSE *)GKI_getbuf(sizeof(tBTA_FTC_API_CLOSE))) != NULL) + { + p_buf->hdr.event = BTA_FTC_API_CLOSE_EVT; + p_buf->suspend = FALSE; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcCopyFile +** +** Description Invoke a Copy action on the server. +** Create a copy of p_src and name it as p_dest +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcCopyFile(const char *p_src, const char *p_dest) +{ + tBTA_FTC_API_ACTION *p_buf; + UINT16 src_len = (p_src) ? strlen(p_src) : 0; + UINT16 dest_len = (p_dest) ? strlen(p_dest) : 0; + UINT16 total_len = sizeof(tBTA_FTC_API_ACTION) + src_len + dest_len + 2; + + APPL_TRACE_DEBUG2("BTA_FtcCopyFile src:%s, dest:%s", p_src, p_dest); + + if ((p_buf = (tBTA_FTC_API_ACTION *)GKI_getbuf( total_len)) != NULL) + { + p_buf->hdr.event = BTA_FTC_API_ACTION_EVT; + p_buf->action = BTA_FT_ACT_COPY; + p_buf->p_src = (char *)(p_buf + 1); + p_buf->p_dest = (char *)(p_buf->p_src + src_len + 1); + /* copy the src name */ + if (p_src) + { + BCM_STRNCPY_S(p_buf->p_src, src_len+1, p_src, src_len); + p_buf->p_src[src_len] = '\0'; + } + else + p_buf->p_src[0] = '\0'; + + /* copy the dest name */ + if (p_dest) + { + BCM_STRNCPY_S(p_buf->p_dest, dest_len+1, p_dest, dest_len); + p_buf->p_dest[dest_len] = '\0'; + } + else + p_buf->p_dest[0] = '\0'; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcMoveFile +** +** Description Invoke a Move action on the server. +** Move/rename p_src to p_dest +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcMoveFile(const char *p_src, const char *p_dest) +{ + tBTA_FTC_API_ACTION *p_buf; + UINT16 src_len = (p_src) ? strlen(p_src) : 0; + UINT16 dest_len = (p_dest) ? strlen(p_dest) : 0; + UINT16 total_len = sizeof(tBTA_FTC_API_ACTION) + src_len + dest_len + 2; + + APPL_TRACE_DEBUG2("BTA_FtcMoveFile src:%s, dest:%s", p_src, p_dest); + + if ((p_buf = (tBTA_FTC_API_ACTION *)GKI_getbuf(total_len)) != NULL) + { + p_buf->hdr.event = BTA_FTC_API_ACTION_EVT; + p_buf->action = BTA_FT_ACT_MOVE; + p_buf->p_src = (char *)(p_buf + 1); + p_buf->p_dest = (char *)(p_buf->p_src + src_len + 1); + + /* copy the src name */ + if (p_src) + { + BCM_STRNCPY_S(p_buf->p_src, src_len+1, p_src, src_len); + p_buf->p_src[src_len] = '\0'; + } + else + p_buf->p_src[0] = '\0'; + + /* copy the dest name */ + if (p_dest) + { + BCM_STRNCPY_S(p_buf->p_dest, dest_len+1, p_dest, dest_len); + p_buf->p_dest[dest_len] = '\0'; + } + else + p_buf->p_dest[0] = '\0'; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcSetPermission +** +** Description Invoke a SetPermission action on the server. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcSetPermission(const char *p_src, UINT8 user, UINT8 group, UINT8 other) +{ + tBTA_FTC_API_ACTION *p_buf; + UINT16 src_len = (p_src) ? strlen(p_src) : 0; + UINT16 total_len = sizeof(tBTA_FTC_API_ACTION) + src_len + 1; + + APPL_TRACE_DEBUG4("BTA_FtcSetPermission src:%s, user:0x%x, group:0x%x, other:0x%x", + p_src, user, group, other); + + if ((p_buf = (tBTA_FTC_API_ACTION *)GKI_getbuf(total_len)) != NULL) + { + p_buf->hdr.event = BTA_FTC_API_ACTION_EVT; + p_buf->action = BTA_FT_ACT_PERMISSION; + p_buf->p_src = (char *)(p_buf + 1); + + /* copy the src name */ + if (p_src) + { + BCM_STRNCPY_S(p_buf->p_src, src_len+1, p_src, src_len); + p_buf->p_src[src_len] = '\0'; + } + else + p_buf->p_src[0] = '\0'; + + p_buf->permission[0] = user; + p_buf->permission[1] = group; + p_buf->permission[2] = other; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtcPutFile +** +** Description Send a file to the connected server. +** This function can only be used when the client is connected +** in FTP, OPP and BIP mode. +** +** Note: File name is specified with a fully qualified path. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcPutFile(const char *p_name, tBTA_FTC_PARAM *p_param) +{ + tBTA_FTC_DATA *p_msg; + INT32 name_len = (INT32)((p_bta_fs_cfg->max_path_len + 1 + 3)/4)*4; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + sizeof(tBTA_FTC_PARAM) + name_len))) != NULL) + { + p_msg->api_put.p_name = (char *)(p_msg + 1); + + if (p_name != NULL) + BCM_STRNCPY_S(p_msg->api_put.p_name, name_len, p_name, p_bta_fs_cfg->max_path_len); + else + p_msg->api_put.p_name[0] = 0; + + if(p_param) + { + p_msg->api_put.p_param = (tBTA_FTC_PARAM *)(p_msg->api_put.p_name + name_len); + memcpy(p_msg->api_put.p_param, p_param, sizeof(tBTA_FTC_PARAM)); + } + else + p_msg->api_put.p_param = NULL; + + p_msg->api_put.hdr.event = BTA_FTC_API_PUTFILE_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcGetPhoneBook +** +** Description Retrieve a PhoneBook from the peer device and copy it to the +** local file system. +** +** This function can only be used when the client is connected +** in PBAP mode. +** +** Note: local file name is specified with a fully qualified path. +** Remote file name is absolute path in UTF-8 format. +** (telecom/pb.vcf or SIM1/telecom/pb.vcf). +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcGetPhoneBook(char *p_local_name, char *p_remote_name, + tBTA_FTC_FILTER_MASK filter, tBTA_FTC_FORMAT format, + UINT16 max_list_count, UINT16 list_start_offset) +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_GET *p_get; + tBTA_FTC_GET_PARAM *p_getp; + UINT16 remote_name_length = (p_remote_name) ? strlen(p_remote_name) : 0; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + (p_bta_fs_cfg->max_path_len + 1) + remote_name_length + 1))) != NULL) + { + p_get = &p_msg->api_get; + p_get->p_param = (tBTA_FTC_GET_PARAM *)(p_msg + 1); + p_getp = p_get->p_param; + p_get->p_rem_name = (char *)(p_getp + 1); + p_get->p_name = (char *)(p_get->p_rem_name + remote_name_length + 1); + p_get->obj_type = BTA_FTC_GET_PB; + + /* copy the local name */ + if (p_local_name) + BCM_STRNCPY_S(p_get->p_name, p_bta_fs_cfg->max_path_len + 1, p_local_name, p_bta_fs_cfg->max_path_len); + else + p_get->p_name[0] = '\0'; + + /* copy remote name */ + if( p_remote_name) + BCM_STRNCPY_S(p_get->p_rem_name, remote_name_length + 1, p_remote_name, remote_name_length); + p_get->p_rem_name[remote_name_length] = '\0'; + + p_getp->filter = filter; + p_getp->format = format; + p_getp->list_start_offset = list_start_offset; + p_getp->max_list_count = max_list_count; + + p_get->hdr.event = BTA_FTC_API_GETFILE_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcGetCard +** +** Description Retrieve a vCard from the peer device and copy it to the +** local file system. +** +** This function can only be used when the client is connected +** in PBAP mode. +** +** Note: local file name is specified with a fully qualified path. +** Remote file name is relative path in UTF-8 format. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcGetCard(char *p_local_name, char *p_remote_name, + tBTA_FTC_FILTER_MASK filter, tBTA_FTC_FORMAT format) +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_GET *p_get; + tBTA_FTC_GET_PARAM *p_getp; + UINT16 remote_name_length = (p_remote_name) ? strlen(p_remote_name) : 0; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + (p_bta_fs_cfg->max_path_len + 1) + remote_name_length + 1))) != NULL) + { + p_get = &p_msg->api_get; + p_get->p_param = (tBTA_FTC_GET_PARAM *)(p_msg + 1); + p_getp = p_get->p_param; + p_get->p_rem_name = (char *)(p_getp + 1); + p_get->p_name = (char *)(p_get->p_rem_name + remote_name_length + 1); + p_get->obj_type = BTA_FTC_GET_CARD; + + /* copy the local name */ + if (p_local_name) + { + BCM_STRNCPY_S(p_get->p_name, p_bta_fs_cfg->max_path_len + 1, p_local_name, p_bta_fs_cfg->max_path_len); + p_get->p_name[p_bta_fs_cfg->max_path_len] = '\0'; + } + else + p_get->p_name[0] = '\0'; + + /* copy remote name */ + if( p_remote_name) + BCM_STRNCPY_S(p_get->p_rem_name, remote_name_length+1, p_remote_name, remote_name_length); + p_get->p_rem_name[remote_name_length] = '\0'; + + p_getp->filter = filter; + p_getp->format = format; + + p_get->hdr.event = BTA_FTC_API_GETFILE_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcGetFile +** +** Description Retrieve a file from the peer device and copy it to the +** local file system. +** +** This function can only be used when the client is connected +** in FTP mode. +** +** Note: local file name is specified with a fully qualified path. +** Remote file name is specified in UTF-8 format. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcGetFile(char *p_local_name, char *p_remote_name) +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_GET *p_get; + UINT16 remote_name_length = (p_remote_name) ? strlen(p_remote_name) : 0; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + (p_bta_fs_cfg->max_path_len + 1) + remote_name_length + 1))) != NULL) + { + p_get = &p_msg->api_get; + p_get->obj_type = BTA_FTC_GET_FILE; + p_get->p_param = NULL; + p_get->p_rem_name = (char *)(p_msg + 1); + p_get->p_name = (char *)(p_msg->api_get.p_rem_name + remote_name_length + 1); + + /* copy the local name */ + if (p_local_name) + { + BCM_STRNCPY_S(p_get->p_name, p_bta_fs_cfg->max_path_len + 1, p_local_name, p_bta_fs_cfg->max_path_len); + p_get->p_name[p_bta_fs_cfg->max_path_len] = '\0'; + } + else + p_get->p_name[0] = '\0'; + + /* copy remote name */ + if( p_remote_name) + BCM_STRNCPY_S(p_get->p_rem_name, remote_name_length+1, p_remote_name, remote_name_length); + p_get->p_rem_name[remote_name_length] = '\0'; + + + p_get->hdr.event = BTA_FTC_API_GETFILE_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcChDir +** +** Description Change directory on the peer device. +** +** This function can only be used when the client is connected +** in FTP and PBAP mode. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcChDir(char *p_dir, tBTA_FTC_FLAG flag) +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_CHDIR *p_chdir; + UINT16 dir_len; + + /* If directory is specified set the length */ + dir_len = (p_dir && *p_dir != '\0') ? (UINT16)(strlen(p_dir) + 1): 0; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + dir_len))) != NULL) + { + p_chdir = &p_msg->api_chdir; + p_chdir->flag = flag; + if (dir_len) + { + p_chdir->p_dir = (char *)(p_msg + 1); + BCM_STRNCPY_S(p_chdir->p_dir, dir_len, p_dir, dir_len); + } + else /* Setting to root directory OR backing up a directory */ + p_chdir->p_dir = NULL; + + p_chdir->hdr.event = BTA_FTC_API_CHDIR_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcAuthRsp +** +** Description Sends a response to an OBEX authentication challenge to the +** connected OBEX server. Called in response to an BTA_FTC_AUTH_EVT +** event. +** +** Note: If the "userid_required" is TRUE in the BTA_FTC_AUTH_EVT event, +** then p_userid is required, otherwise it is optional. +** +** p_password must be less than BTA_FTC_MAX_AUTH_KEY_SIZE (16 bytes) +** p_userid must be less than OBX_MAX_REALM_LEN (defined in target.h) +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcAuthRsp (char *p_password, char *p_userid) +{ + tBTA_FTC_API_AUTHRSP *p_auth_rsp; + + if ((p_auth_rsp = (tBTA_FTC_API_AUTHRSP *)GKI_getbuf(sizeof(tBTA_FTC_API_AUTHRSP))) != NULL) + { + memset(p_auth_rsp, 0, sizeof(tBTA_FTC_API_AUTHRSP)); + + p_auth_rsp->hdr.event = BTA_FTC_API_AUTHRSP_EVT; + + if (p_password) + { + p_auth_rsp->key_len = strlen(p_password); + if (p_auth_rsp->key_len > BTA_FTC_MAX_AUTH_KEY_SIZE) + p_auth_rsp->key_len = BTA_FTC_MAX_AUTH_KEY_SIZE; + memcpy(p_auth_rsp->key, p_password, p_auth_rsp->key_len); + } + + if (p_userid) + { + p_auth_rsp->userid_len = strlen(p_userid); + if (p_auth_rsp->userid_len > OBX_MAX_REALM_LEN) + p_auth_rsp->userid_len = OBX_MAX_REALM_LEN; + memcpy(p_auth_rsp->userid, p_userid, p_auth_rsp->userid_len); + } + + bta_sys_sendmsg(p_auth_rsp); + } +} + +/******************************************************************************* +** +** Function BTA_FtcListCards +** +** Description Retrieve a directory listing from the peer device. +** When the operation is complete the callback function will +** be called with one or more BTA_FTC_LIST_EVT events +** containing directory list information formatted as described +** in the PBAP Spec, Version 0.9, section 3.1.6. +** This function can only be used when the client is connected +** to a peer device. +** +** This function can only be used when the client is connected +** in PBAP mode. +** +** Parameters p_dir - Name of directory to retrieve listing of. +** +** Returns void +** +*******************************************************************************/ + +void BTA_FtcListCards(char *p_dir, tBTA_FTC_ORDER order, char *p_value, + tBTA_FTC_ATTR attribute, UINT16 max_list_count, + UINT16 list_start_offset) +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_LIST *p_list; + tBTA_FTC_LST_PARAM *p_param; + UINT16 dir_len = (p_dir == NULL) ? 0 : strlen(p_dir) ; + UINT16 value_len = (p_value == NULL) ? 0 : strlen(p_value) ; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + sizeof(tBTA_FTC_LST_PARAM) + + dir_len + value_len + 2))) != NULL) + { + p_list = &p_msg->api_list; + p_list->p_param = (tBTA_FTC_LST_PARAM *)(p_msg + 1); + p_param = p_list->p_param; + p_list->p_dir = (char *)(p_param + 1); + p_param->order = order; + p_param->attribute = attribute; + p_param->max_list_count = max_list_count; + p_param->list_start_offset = list_start_offset; + + if (dir_len) + BCM_STRNCPY_S(p_list->p_dir, dir_len+1, p_dir, dir_len); + p_list->p_dir[dir_len] = 0; + + if (value_len) + { + p_param->p_value = (char *)(p_list->p_dir + dir_len + 1); + BCM_STRNCPY_S(p_param->p_value, value_len+1, p_value, value_len); + p_param->p_value[value_len] = 0; + } + else + p_param->p_value = NULL; + + p_list->hdr.event = BTA_FTC_API_LISTDIR_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcListDir +** +** Description Retrieve a directory listing from the peer device. +** When the operation is complete the callback function will +** be called with one or more BTA_FTC_LIST_EVT events +** containing directory list information formatted as described +** in the IrOBEX Spec, Version 1.2, section 9.1.2.3. +** +** This function can only be used when the client is connected +** in FTP mode. +** +** Parameters p_dir - Name of directory to retrieve listing of. If NULL, +** the current working directory is retrieved. +** +** Returns void +** +*******************************************************************************/ + +void BTA_FtcListDir(char *p_dir) +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_LIST *p_list; + UINT16 dir_len = (p_dir == NULL) ? 0 : strlen(p_dir) ; + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + dir_len + 1))) != NULL) + { + p_list = &p_msg->api_list; + p_list->p_dir = (char *)(p_msg + 1); + p_list->p_param = NULL; + + if (dir_len) + BCM_STRNCPY_S(p_list->p_dir, dir_len+1, p_dir, dir_len); + + p_list->p_dir[dir_len] = 0; + + p_list->hdr.event = BTA_FTC_API_LISTDIR_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_FtcMkDir +** +** Description Create a directory on the peer device. When the operation is +** complete the status is returned with the BTA_FTC_MKDIR_EVT +** event. +** +** This function can only be used when the client is connected +** in FTP mode. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcMkDir(char *p_dir) +{ + tBTA_FTC_API_MKDIR *p_mkdir; + UINT16 len = (p_dir == NULL) ? 0: strlen(p_dir); + + if ((p_mkdir = (tBTA_FTC_API_MKDIR *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_API_MKDIR) + + len + 1))) != NULL) + { + p_mkdir->p_dir = (char *)(p_mkdir + 1); + + if (len > 0) + BCM_STRNCPY_S(p_mkdir->p_dir, len+1, p_dir, len); + + p_mkdir->p_dir[len] = 0; + + p_mkdir->hdr.event = BTA_FTC_API_MKDIR_EVT; + bta_sys_sendmsg(p_mkdir); + } +} + +/******************************************************************************* +** +** Function BTA_FtcRemove +** +** Description Remove a file or directory on the peer device. When the +** operation is complete the status is returned with the +** BTA_FTC_REMOVE_EVT event. +** +** This function can only be used when the client is connected +** in FTP mode. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcRemove(char *p_name) + +{ + tBTA_FTC_DATA *p_msg; + tBTA_FTC_API_REMOVE *p_remove; + UINT16 len = (p_name == NULL) ? 0 :strlen(p_name); + + if ((p_msg = (tBTA_FTC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_FTC_DATA) + + len + 1))) != NULL) + { + p_remove = &p_msg->api_remove; + p_remove->p_name = (char *)(p_msg +1); + if(len) + BCM_STRNCPY_S(p_remove->p_name, len+1, p_name, len); + + p_remove->p_name[len] = 0; + + p_remove->hdr.event = BTA_FTC_API_REMOVE_EVT; + bta_sys_sendmsg(p_msg); + } +} + + + + +/******************************************************************************* +** +** Function BTA_FtcAbort +** +** Description Aborts any active Put or Get file operation. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtcAbort(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_FTC_API_ABORT_EVT; + bta_sys_sendmsg(p_buf); + } +} +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_ftc_int.h b/bta/ft/bta_ftc_int.h new file mode 100644 index 0000000..4279aa6 --- /dev/null +++ b/bta/ft/bta_ftc_int.h @@ -0,0 +1,504 @@ +/***************************************************************************** +** +** Name: bta_ftc_int.h +** +** Description: This is the private file for the file transfer +** client (FTC). +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_FTC_INT_H +#define BTA_FTC_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_ft_api.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) +#include "bta_bi_api.h" +#endif + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +#define BTA_FTC_PB_ACCESS_TARGET_UUID "\x79\x61\x35\xF0\xF0\xC5\x11\xD8\x09\x66\x08\x00\x20\x0C\x9A\x66" +#define BTA_FTC_FOLDER_BROWSING_TARGET_UUID "\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09" +#define BTA_FTC_UUID_LENGTH 16 +#define BTA_FTC_MAX_AUTH_KEY_SIZE 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */ +#define BTA_FTC_DEFAULT_VERSION 0x0100 /* for PBAP PCE */ + +#define BTA_FTC_FOLDER_LISTING_TYPE "x-obex/folder-listing" + +#define BTA_FTC_PULL_PB_TYPE "x-bt/phonebook" +#define BTA_FTC_PULL_VCARD_LISTING_TYPE "x-bt/vcard-listing" +#define BTA_FTC_PULL_VCARD_ENTRY_TYPE "x-bt/vcard" + +/* FTC Active ftp obex operation (Valid in connected state) */ +#define FTC_OP_NONE 0 +#define FTC_OP_GET_FILE 1 +#define FTC_OP_PUT_FILE 2 +#define FTC_OP_DELETE 3 /* Folder or File */ +#define FTC_OP_GET_LIST 4 +#define FTC_OP_MKDIR 5 +#define FTC_OP_CHDIR 6 +/* note: the following 3 OPs need to be continuous and the order can not change */ +#define FTC_OP_COPY 7 /* Copy object */ +#define FTC_OP_MOVE 8 /* Move/rename object */ +#define FTC_OP_PERMISSION 9 /* Set object permission */ +#define FTC_OP_RESUME 0x80 /* to mark the operation to resume */ + +enum +{ + BTA_FTC_GET_FILE, /* get file */ + BTA_FTC_GET_CARD, /* PBAP PullvCardEntry */ + BTA_FTC_GET_PB /* PBAP PullPhoneBook */ +}; +typedef UINT8 tBTA_FTC_TYPE; + +/* Response Timer Operations */ +#define FTC_TIMER_OP_STOP 0 +#define FTC_TIMER_OP_ABORT 1 +#define FTC_TIMER_OP_SUSPEND 2 + +/* File abort mask states */ +/* Abort must receive cout and response before abort completed */ +#define FTC_ABORT_REQ_NOT_SENT 0x1 +#define FTC_ABORT_REQ_SENT 0x2 +#define FTC_ABORT_RSP_RCVD 0x4 +#define FTC_ABORT_COUT_DONE 0x8 + +#define FTC_ABORT_COMPLETED (FTC_ABORT_REQ_SENT | FTC_ABORT_RSP_RCVD | FTC_ABORT_COUT_DONE) + +/* TODO remove: Reliable session suspend mask states */ +/* suspend must receive cout and response before suspend completed +#define FTC_SUSPEND_REQ_NOT_SENT 0x10 */ + +/* state machine events */ +enum +{ + /* these events are handled by the state machine */ + BTA_FTC_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_FTC), + + BTA_FTC_API_OPEN_EVT, /* Open a connection request */ + BTA_FTC_API_CLOSE_EVT, /* Close an open connection request */ + BTA_FTC_API_PUTFILE_EVT, /* Put File request */ + BTA_FTC_API_GETFILE_EVT, /* Get File request */ + BTA_FTC_API_LISTDIR_EVT, /* List Directory request */ + BTA_FTC_API_CHDIR_EVT, /* Change Directory request */ + BTA_FTC_API_MKDIR_EVT, /* make Directory request */ + BTA_FTC_API_REMOVE_EVT, /* Remove Directory request */ + BTA_FTC_API_AUTHRSP_EVT, /* Response to password request */ + BTA_FTC_API_ABORT_EVT, /* Abort request */ + BTA_FTC_API_ACTION_EVT, /* Action request */ + BTA_FTC_OBX_ACTION_RSP_EVT, /* Copy/Move File or Set Permission */ + BTA_FTC_CI_SESSION_EVT, /* Call-in response to session requests */ + BTA_FTC_SDP_OK_EVT, /* Service search was successful */ + BTA_FTC_SDP_FAIL_EVT, /* Service search failed */ + BTA_FTC_SDP_NEXT_EVT, /* Try another service search (OPP) */ + BTA_FTC_CI_WRITE_EVT, /* Call-in response to Write request */ + BTA_FTC_CI_READ_EVT, /* Call-in response to Read request */ + BTA_FTC_CI_OPEN_EVT, /* Call-in response to File Open request */ + BTA_FTC_OBX_CONN_RSP_EVT, /* OBX Channel Connect Request */ + BTA_FTC_OBX_ABORT_RSP_EVT, /* OBX_operation aborted */ + BTA_FTC_OBX_TOUT_EVT, /* OBX Operation Timeout */ + BTA_FTC_OBX_PASSWORD_EVT, /* OBX password requested */ + BTA_FTC_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */ + BTA_FTC_OBX_PUT_RSP_EVT, /* Write file data or delete */ + BTA_FTC_OBX_GET_RSP_EVT, /* Read file data or folder listing */ + BTA_FTC_OBX_SETPATH_RSP_EVT, /* Make or Change Directory */ + BTA_FTC_OBX_CMPL_EVT, /* operation has completed */ + BTA_FTC_CLOSE_CMPL_EVT, /* Finish the closing of the channel */ + BTA_FTC_DISABLE_CMPL_EVT, /* Finished disabling system */ + BTA_FTC_RSP_TOUT_EVT, /* Timeout waiting for response from server */ + + /* these events are handled outside the state machine */ + BTA_FTC_API_ENABLE_EVT +}; + + +/* state machine states */ +enum +{ + BTA_FTC_IDLE_ST = 0, /* Idle */ + BTA_FTC_W4_CONN_ST, /* Waiting for an Obex connect response */ + BTA_FTC_CONN_ST, /* Connected - FTP Session is active */ + BTA_FTC_SUSPENDING_ST, /* suspend is in progress */ + BTA_FTC_CLOSING_ST /* Closing is in progress */ +}; +typedef UINT16 tBTA_FTC_INT_EVT; + +typedef UINT8 tBTA_FTC_STATE; + +/* Application Parameters Header +Tag IDs used in the Application Parameters header: +*/ + /* Tag ID Length Possible Values */ +#define BTA_FTC_APH_ORDER 0x01 /* Order 1 bytes 0x0 to 0x2 */ +#define BTA_FTC_APH_SEARCH_VALUE 0x02 /* SearchValue variable text */ +#define BTA_FTC_APH_SEARCH_ATTR 0x03 /* SearchAttribute 1 byte 0x0 to 0x2 */ +#define BTA_FTC_APH_MAX_LIST_COUNT 0x04 /* MaxListCount 2 bytes 0x0000 to 0xFFFF */ +#define BTA_FTC_APH_LIST_STOFF 0x05 /* ListStartOffset 2 bytes 0x0000 to 0xFFFF */ +#define BTA_FTC_APH_FILTER 0x06 /* Filter 4 bytes 0x00000000 to 0xFFFFFFFF */ +#define BTA_FTC_APH_FORMAT 0x07 /* Format 1 byte 0x00(2.1), 0x01(3.0) */ +#define BTA_FTC_APH_PB_SIZE 0x08 /* PhoneBookSize 2 byte 0x0000 to 0xFFFF */ +#define BTA_FTC_APH_NEW_MISSED_CALL 0x09 /* NewMissedCall 1 bytes 0x00 to 0xFF */ +#define BTA_FTC_APH_MAX_TAG BTA_FTC_APH_NEW_MISSED_CALL + +/* data type for BTA_FTC_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_FTC_CBACK *p_cback; + UINT8 app_id; +} tBTA_FTC_API_ENABLE; + +/* data type for BTA_FTC_API_OPEN_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_SERVICE_MASK services; /* FTP and/or OPP */ + BD_ADDR bd_addr; + UINT8 sec_mask; + BOOLEAN srm; + UINT32 nonce; +} tBTA_FTC_API_OPEN; + +/* data type for BTA_FTC_API_CLOSE_EVT */ +typedef struct +{ + BT_HDR hdr; + BOOLEAN suspend; +} tBTA_FTC_API_CLOSE; + +/* data type for BTA_FTC_API_ACTION_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_FTC_ACT action; + char *p_src; /* UTF-8 name from listing */ + char *p_dest; /* UTF-8 name */ + UINT8 permission[3]; +} tBTA_FTC_API_ACTION; + +/* data type for BTA_FTC_API_PUTFILE_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_name; + tBTA_FTC_PARAM *p_param; +} tBTA_FTC_API_PUT; + +typedef struct +{ + tBTA_FTC_FILTER_MASK filter; + UINT16 max_list_count; + UINT16 list_start_offset; + tBTA_FTC_FORMAT format; +} tBTA_FTC_GET_PARAM; + +/* data type for BTA_FTC_API_GETFILE_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_rem_name; /* UTF-8 name from listing */ + char *p_name; + tBTA_FTC_GET_PARAM *p_param; + UINT8 obj_type; +} tBTA_FTC_API_GET; + +/* data type for BTA_FTC_API_CHDIR_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_dir; /* UTF-8 name from listing */ + tBTA_FTC_FLAG flag; +} tBTA_FTC_API_CHDIR; + +typedef struct +{ + char *p_value; + UINT16 max_list_count; + UINT16 list_start_offset; + tBTA_FTC_ORDER order; + tBTA_FTC_ATTR attribute; +} tBTA_FTC_LST_PARAM; + +/* data type for BTA_FTC_API_LISTDIR_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_dir; /* UTF-8 name from listing */ + tBTA_FTC_LST_PARAM *p_param; +} tBTA_FTC_API_LIST; + +/* data type for BTA_FTC_API_MKDIR_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_dir; /* UTF-8 name directory */ +} tBTA_FTC_API_MKDIR; + +/* data type for BTA_FTC_API_REMOVE_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_name; /* UTF-8 name of file or directory */ +} tBTA_FTC_API_REMOVE; + + +/* data type for BTA_FTC_API_AUTHRSP_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 key [BTA_FTC_MAX_AUTH_KEY_SIZE]; /* The authentication key.*/ + UINT8 key_len; + UINT8 userid [OBX_MAX_REALM_LEN]; /* The authentication user id.*/ + UINT8 userid_len; +} tBTA_FTC_API_AUTHRSP; + +/* data type for BTA_FTC_SDP_OK_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 scn; + UINT16 psm; + UINT16 version; +} tBTA_FTC_SDP_OK_EVT; + +/* data type for all obex events + hdr.event contains the FTC event +*/ +typedef struct +{ + BT_HDR hdr; + tOBX_HANDLE handle; + tOBX_EVT_PARAM param; + BT_HDR *p_pkt; + tOBX_EVENT obx_event; + UINT8 rsp_code; +} tBTA_FTC_OBX_EVT; + +/* union of all event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_FTC_API_ENABLE api_enable; + tBTA_FTC_API_OPEN api_open; + tBTA_FTC_API_CLOSE api_close; + tBTA_FTC_API_PUT api_put; + tBTA_FTC_API_GET api_get; + tBTA_FTC_API_CHDIR api_chdir; + tBTA_FTC_API_MKDIR api_mkdir; + tBTA_FTC_API_REMOVE api_remove; + tBTA_FTC_API_AUTHRSP auth_rsp; + tBTA_FTC_API_LIST api_list; + tBTA_FTC_API_ACTION api_action; + tBTA_FTC_SDP_OK_EVT sdp_ok; + tBTA_FTC_OBX_EVT obx_evt; + tBTA_FS_CI_OPEN_EVT open_evt; + tBTA_FS_CI_RESUME_EVT resume_evt; + tBTA_FS_CI_READ_EVT read_evt; + tBTA_FS_CI_WRITE_EVT write_evt; +} tBTA_FTC_DATA; + + +/* OBX Response Packet Structure - Holds current command/response packet info */ +typedef struct +{ + BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */ + UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */ + UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */ + UINT16 bytes_left; /* (Get/Put) Holds bytes available left in Obx packet */ + BOOLEAN final_pkt; /* (Get) Holds the final bit of the Put packet */ +} tBTA_FTC_OBX_PKT; + +/* Power management state for FTC */ +#define BTA_FTC_PM_BUSY 0 +#define BTA_FTC_PM_IDLE 1 + + +/* FTC control block */ +typedef struct +{ + tBTA_FTC_CBACK *p_cback; /* pointer to application callback function */ + char *p_name; /* Holds the local file name */ + tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */ + UINT32 sdp_handle; /* SDP record handle for PCE */ + tBTA_FTC_OBX_PKT obx; /* Holds the current OBX packet information */ + TIMER_LIST_ENT rsp_timer; /* response timer */ + tBTA_SERVICE_MASK services; /* FTP and/or OPP and/or BIP */ + int fd; /* File Descriptor of opened file */ + UINT32 file_size; /* (Put/Get) length of file */ +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + tBIP_IMAGING_CAPS *p_caps; /* BIP imaging capabilities */ + tBIP_IMG_HDL_STR img_hdl; /* The image’s handle for when responder requests thumbnail */ +#endif + UINT8 *p_sess_info; + UINT16 peer_mtu; + UINT16 sdp_service; + BD_ADDR bd_addr; + tOBX_HANDLE obx_handle; + UINT8 sec_mask; + tBTA_FTC_STATE state; /* state machine state */ + UINT8 obx_oper; /* current active OBX operation PUT FILE or GET FILE */ + UINT8 timer_oper; /* current active response timer action (abort or close) */ + UINT8 app_id; + tBTA_FTC_TYPE obj_type; /* type of get op */ + BOOLEAN first_req_pkt; /* TRUE if retrieving the first packet of GET/PUT file */ + BOOLEAN cout_active; /* TRUE if call-out is currently active */ + BOOLEAN disabling; /* TRUE if client is in process of disabling */ + UINT8 aborting; /* Non-zero if client is in process of aborting */ + BOOLEAN int_abort; /* TRUE if internal abort issued (Not API inititated) */ + BOOLEAN is_enabled; /* TRUE if client is enabled */ + BOOLEAN req_pending; /* TRUE when waiting for an obex response */ + BOOLEAN sdp_pending; /* TRUE when waiting for SDP to complete */ +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + UINT8 bic_handle; +#endif + UINT8 scn; + UINT16 version; + + /* OBEX 1.5 */ + UINT16 psm; + UINT32 nonce; + BOOLEAN srm; + BOOLEAN suspending; /* TRUE when suspending session */ + + tBTA_FTC_STATUS status; + UINT8 pm_state; +} tBTA_FTC_CB; + +/* type for action functions */ +typedef void (*tBTA_FTC_ACTION)(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); + +/****************************************************************************** +** Configuration Definitions +*******************************************************************************/ +typedef const tBTA_FTC_ACTION (*tBTA_FTC_BI_TBL); + +/* Configuration structure */ +typedef struct +{ + tBTA_FTC_BI_TBL p_bi_action; /* BI related action func used in FTC */ + UINT8 realm_charset; /* Server only */ + BOOLEAN userid_req; /* TRUE if user id is required during obex authentication (Server only) */ + BOOLEAN auto_file_list; /* TRUE if automatic get the file listing from sever on OBEX connect response */ + UINT8 pce_features; /* PBAP PCE supported features. If 0, PCE is not supported */ + char *pce_name; /* service name for PBAP PCE SDP record */ + INT32 abort_tout; /* Timeout in milliseconds to wait for abort OBEX response (client only) */ + INT32 stop_tout; /* Timeout in milliseconds to wait for close OBEX response (client only) */ + INT32 suspend_tout; /* Timeout in milliseconds to wait for suspend OBEX response (client only) */ + UINT32 nonce; /* non-0 to allow reliable session (Server Only) */ + UINT8 max_suspend; /* the maximum number of suspended session (Server Only) */ + BOOLEAN over_l2cap; /* TRUE to use Obex Over L2CAP (Server Only) */ + BOOLEAN srm; /* TRUE to engage Single Response Mode (Server Only) */ + +} tBTA_FT_CFG; + +enum +{ + BTA_FTC_BI_REGISTER_IDX = 0, + BTA_FTC_BI_DEREGISTER_IDX, + BTA_FTC_BI_AUTHRSP_IDX, + BTA_FTC_BI_FREEXML_IDX, + BTA_FTC_BI_PUT_IDX, + BTA_FTC_BI_ABORT_IDX +}; + +extern const tBTA_FTC_ACTION bta_ftc_bi_action[]; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* FTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_FTC_CB bta_ftc_cb; +#else +extern tBTA_FTC_CB *bta_ftc_cb_ptr; +#define bta_ftc_cb (*bta_ftc_cb_ptr) +#endif + +/* FT configuration constants */ +extern tBTA_FT_CFG *p_bta_ft_cfg; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +extern BOOLEAN bta_ftc_hdl_event(BT_HDR *p_msg); +extern void bta_ftc_sm_execute(tBTA_FTC_CB *p_cb, UINT16 event, + tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event, + UINT8 rsp_code, tOBX_EVT_PARAM param, + BT_HDR *p_pkt); + +extern void bta_ftc_init_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_init_close(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_init_putfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_init_getfile(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_chdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_send_authrsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_api_action(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_action_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_get_srm_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_ci_write_srm(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_ci_write(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_ci_read(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_ci_open(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_ci_resume(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_conn_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_sess_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_suspended(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_abort_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_password(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_put_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_obx_setpath_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_initialize(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_trans_cmpl(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_stop_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_start_client(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_free_db(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_ignore_obx(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_find_service(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_close(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_open_fail(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_close_complete(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_set_disable(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_rsp_timeout(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_put(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_abort(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); + +/* BI related action function used in FTC */ +extern void bta_ftc_bic_register(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_deregister(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_authrsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_freexml(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_putact(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_bic_abortact(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); + + +extern void bta_ftc_listdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_remove(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern void bta_ftc_mkdir(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); + +/* miscellaneous functions */ +extern UINT8 bta_ftc_send_get_req(tBTA_FTC_CB *p_cb); +extern void bta_ftc_proc_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data); +extern UINT8 bta_ftc_cont_put_file(tBTA_FTC_CB *p_cb, BOOLEAN first_pkt); +extern void bta_ftc_proc_list_data(tBTA_FTC_CB *p_cb, tBTA_FTC_OBX_EVT *p_evt); +extern void bta_ftc_get_listing(tBTA_FTC_CB *p_cb, char *p_name, tBTA_FTC_LST_PARAM *p_param); +extern void bta_ftc_listing_err(BT_HDR **p_pkt, tBTA_FTC_STATUS status); + + +extern tBTA_FTC_STATUS bta_ftc_convert_obx_to_ftc_status(tOBX_STATUS obx_status); + +#endif /* BTA_FTC_INT_H */ diff --git a/bta/ft/bta_ftc_main.c b/bta/ft/bta_ftc_main.c new file mode 100644 index 0000000..8148703 --- /dev/null +++ b/bta/ft/bta_ftc_main.c @@ -0,0 +1,689 @@ +/***************************************************************************** +** +** Name: bta_ftc_main.c +** +** Description: This file contains the file transfer client main functions +** and state machine. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#include <string.h> + +#include "bt_target.h" + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include "bta_ftc_int.h" +#include "gki.h" +#include "obx_api.h" + + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + + +/* state machine action enumeration list */ +enum +{ + BTA_FTC_INIT_OPEN, + BTA_FTC_START_CLIENT, + BTA_FTC_STOP_CLIENT, + BTA_FTC_INIT_GETFILE, + BTA_FTC_INIT_PUTFILE, + BTA_FTC_LISTDIR, + BTA_FTC_CHDIR, + BTA_FTC_MKDIR, + BTA_FTC_REMOVE, + BTA_FTC_SEND_AUTHRSP, + BTA_FTC_CI_WRITE, + BTA_FTC_CI_READ, + BTA_FTC_CI_OPEN, + BTA_FTC_CI_RESUME, + BTA_FTC_OBX_SESS_RSP, + BTA_FTC_OBX_GET_SRM_RSP, + BTA_FTC_CI_WRITE_SRM, + BTA_FTC_SUSPENDED, + BTA_FTC_OBX_CONN_RSP, + BTA_FTC_CLOSE, + BTA_FTC_OPEN_FAIL, + BTA_FTC_OBX_ABORT_RSP, + BTA_FTC_OBX_PASSWORD, + BTA_FTC_OBX_TIMEOUT, + BTA_FTC_OBX_PUT_RSP, + BTA_FTC_OBX_GET_RSP, + BTA_FTC_OBX_SETPATH_RSP, + BTA_FTC_TRANS_CMPL, + BTA_FTC_FREE_DB, + BTA_FTC_IGNORE_OBX, + BTA_FTC_FIND_SERVICE, + BTA_FTC_INITIALIZE, + BTA_FTC_CLOSE_COMPLETE, + BTA_FTC_BIC_PUT, + BTA_FTC_BIC_ABORT, + BTA_FTC_SET_DISABLE, + BTA_FTC_ABORT, + BTA_FTC_API_ACTION, + BTA_FTC_OBX_ACTION_RSP, + BTA_FTC_RSP_TIMEOUT, + BTA_FTC_IGNORE +}; + +/* action function list */ +const tBTA_FTC_ACTION bta_ftc_action[] = +{ + bta_ftc_init_open, + bta_ftc_start_client, + bta_ftc_stop_client, + bta_ftc_init_getfile, + bta_ftc_init_putfile, + bta_ftc_listdir, + bta_ftc_chdir, + bta_ftc_mkdir, + bta_ftc_remove, + bta_ftc_send_authrsp, + bta_ftc_ci_write, + bta_ftc_ci_read, + bta_ftc_ci_open, + bta_ftc_ci_resume, + bta_ftc_obx_sess_rsp, + bta_ftc_obx_get_srm_rsp, + bta_ftc_ci_write_srm, + bta_ftc_suspended, + bta_ftc_obx_conn_rsp, + bta_ftc_close, + bta_ftc_open_fail, + bta_ftc_obx_abort_rsp, + bta_ftc_obx_password, + bta_ftc_obx_timeout, + bta_ftc_obx_put_rsp, + bta_ftc_obx_get_rsp, + bta_ftc_obx_setpath_rsp, + bta_ftc_trans_cmpl, + bta_ftc_free_db, + bta_ftc_ignore_obx, + bta_ftc_find_service, + bta_ftc_initialize, + bta_ftc_close_complete, + bta_ftc_bic_put, + bta_ftc_bic_abort, + bta_ftc_set_disable, + bta_ftc_abort, + bta_ftc_api_action, + bta_ftc_obx_action_rsp, + bta_ftc_rsp_timeout +}; + + +/* state table information */ +#define BTA_FTC_ACTIONS 2 /* number of actions */ +#define BTA_FTC_NEXT_STATE 2 /* position of next state */ +#define BTA_FTC_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_ftc_st_idle[][BTA_FTC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_INITIALIZE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_INIT_OPEN, BTA_FTC_FIND_SERVICE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST} +}; + +/* state table for wait for authentication response state */ +static const UINT8 bta_ftc_st_w4_conn[][BTA_FTC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_STOP_CLIENT, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_STOP_CLIENT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_BIC_PUT, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_SEND_AUTHRSP, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_BIC_ABORT, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_CI_RESUME, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_START_CLIENT, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_FIND_SERVICE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_OBX_CONN_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_OBX_PASSWORD, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_OPEN_FAIL, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_W4_CONN_ST}, +/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST} + +}; + +/* state table for connected state */ +static const UINT8 bta_ftc_st_connected[][BTA_FTC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_STOP_CLIENT, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_STOP_CLIENT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_INIT_PUTFILE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_INIT_GETFILE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_LISTDIR , BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_CHDIR, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_MKDIR, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_REMOVE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_SEND_AUTHRSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_ABORT, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_API_ACTION, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_OBX_ACTION_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_CI_WRITE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_CI_READ, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_CI_OPEN, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_SUSPENDED, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_OBX_ABORT_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_OBX_PASSWORD, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_CLOSE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_OBX_PUT_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_OBX_GET_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_OBX_SETPATH_RSP, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_TRANS_CMPL, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CONN_ST}, +/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_RSP_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CONN_ST} +}; + +/* state table for suspending state */ +static const UINT8 bta_ftc_st_suspending[][BTA_FTC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_STOP_CLIENT, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_STOP_CLIENT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_CI_WRITE_SRM, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_CI_READ, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_CI_OPEN, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_OBX_SESS_RSP, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_OBX_ABORT_RSP, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_CLOSE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_OBX_PUT_RSP, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_OBX_GET_SRM_RSP, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_SUSPENDING_ST}, +/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_RSP_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST} +}; + +/* state table for closing state */ +static const UINT8 bta_ftc_st_closing[][BTA_FTC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_FTC_API_DISABLE_EVT */ {BTA_FTC_SET_DISABLE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_OPEN_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_CLOSE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_PUTFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_GETFILE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_LISTDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_CHDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_MKDIR_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_REMOVE_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_AUTHRSP_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_ABORT_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_API_ACTION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_ACTION_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_CI_SESSION_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_SDP_OK_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_SDP_FAIL_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_SDP_NEXT_EVT */ {BTA_FTC_FREE_DB, BTA_FTC_CLOSE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_CI_WRITE_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CI_READ_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_CI_OPEN_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_OBX_CONN_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_ABORT_RSP_EVT */ {BTA_FTC_OBX_ABORT_RSP, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_TOUT_EVT */ {BTA_FTC_OBX_TIMEOUT, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_PASSWORD_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_CLOSE_EVT */ {BTA_FTC_CLOSE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_PUT_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_GET_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_SETPATH_RSP_EVT */ {BTA_FTC_IGNORE_OBX, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_OBX_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_CLOSING_ST}, +/* BTA_FTC_CLOSE_CMPL_EVT */ {BTA_FTC_CLOSE_COMPLETE,BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_DISABLE_CMPL_EVT */ {BTA_FTC_IGNORE, BTA_FTC_IGNORE, BTA_FTC_IDLE_ST}, +/* BTA_FTC_RSP_TOUT_EVT */ {BTA_FTC_RSP_TIMEOUT, BTA_FTC_CLOSE_COMPLETE, BTA_FTC_IDLE_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_FTC_ST_TBL)[BTA_FTC_NUM_COLS]; + +/* state table */ +const tBTA_FTC_ST_TBL bta_ftc_st_tbl[] = +{ + bta_ftc_st_idle, + bta_ftc_st_w4_conn, + bta_ftc_st_connected, + bta_ftc_st_suspending, + bta_ftc_st_closing +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* FTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_FTC_CB bta_ftc_cb; +#endif + +#if BTA_FTC_DEBUG == TRUE +static char *ftc_evt_code(tBTA_FTC_INT_EVT evt_code); +static char *ftc_state_code(tBTA_FTC_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_ftc_sm_execute +** +** Description State machine event handling function for FTC +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_sm_execute(tBTA_FTC_CB *p_cb, UINT16 event, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_ST_TBL state_table; + UINT8 action; + int i; +#if BTA_FTC_DEBUG == TRUE + tBTA_FTC_STATE in_state = p_cb->state; + UINT16 in_event = event; + APPL_TRACE_DEBUG4("bta_ftc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state, + ftc_state_code(in_state), + in_event, + ftc_evt_code(in_event)); +#endif + + /* look up the state table for the current state */ + state_table = bta_ftc_st_tbl[p_cb->state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->state = state_table[event][BTA_FTC_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_FTC_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_FTC_IGNORE) + { + (*bta_ftc_action[action])(p_cb, p_data); + } + else + { + break; + } + } + +#if BTA_FTC_DEBUG == TRUE + if (in_state != p_cb->state) + { + APPL_TRACE_DEBUG3("FTC State Change: [%s] -> [%s] after Event [%s]", + ftc_state_code(in_state), + ftc_state_code(p_cb->state), + ftc_evt_code(in_event)); + } +#endif +} + +/***************************************************************************** +** +** Function: bta_ftc_sdp_register() +** +** Purpose: Registers the File Transfer service with SDP +** +** Parameters: +** +** +** Returns: void +** +*****************************************************************************/ +static void bta_ftc_sdp_register (tBTA_FTC_CB *p_cb) +{ + UINT16 pbap_service = UUID_SERVCLASS_PBAP_PCE; + UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + BOOLEAN status = FALSE; + + if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0) + { + APPL_TRACE_WARNING0("FTC SDP: Unable to register PBAP PCE Service"); + return; + } + + /* add service class */ + if (SDP_AddServiceClassIdList(p_cb->sdp_handle, 1, &pbap_service)) + { + status = TRUE; /* All mandatory fields were successful */ + + /* optional: if name is not "", add a name entry */ + if (p_bta_ft_cfg->pce_name && p_bta_ft_cfg->pce_name[0] != '\0') + SDP_AddAttribute(p_cb->sdp_handle, + (UINT16)ATTR_ID_SERVICE_NAME, + (UINT8)TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_bta_ft_cfg->pce_name) + 1), + (UINT8 *)p_bta_ft_cfg->pce_name); + + /* Add in the Bluetooth Profile Descriptor List */ + SDP_AddProfileDescriptorList(p_cb->sdp_handle, + UUID_SERVCLASS_PBAP_PCE, + BTA_FTC_DEFAULT_VERSION); + } /* end of setting mandatory service class */ + + /* Make the service browseable */ + SDP_AddUuidSequence (p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse); + + if (!status) + { + SDP_DeleteRecord(p_cb->sdp_handle); + APPL_TRACE_ERROR0("bta_ftc_sdp_register FAILED"); + p_cb->sdp_handle = 0; + } + else + { + bta_sys_add_uuid( pbap_service ); /* UUID_SERVCLASS_PBAP_PCE */ + APPL_TRACE_DEBUG1("FTC: SDP Registered (handle 0x%08x)", p_cb->sdp_handle); + } + + return; +} + +/******************************************************************************* +** +** Function bta_ftc_api_enable +** +** Description Handle an api enable event. This function enables the FT +** Client by opening an Obex/Rfcomm channel with a peer device. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ftc_api_enable(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + if (!p_cb->is_enabled) + { + /* initialize control block */ + memset(p_cb, 0, sizeof(tBTA_FTC_CB)); + + /* store parameters */ + p_cb->p_cback = p_data->api_enable.p_cback; + p_cb->app_id = p_data->api_enable.app_id; +#if( defined BTA_BI_INCLUDED ) && (BTA_BI_INCLUDED == TRUE) + p_cb->bic_handle = BTA_BIC_INVALID_HANDLE; +#endif + p_cb->fd = BTA_FS_INVALID_FD; + p_cb->is_enabled = TRUE; + + /* create SDP record for PCE */ + if(p_bta_ft_cfg->pce_features) + bta_ftc_sdp_register(p_cb); + } + + /* callback with enable event */ + (*p_cb->p_cback)(BTA_FTC_ENABLE_EVT, 0); +} + +/******************************************************************************* +** +** Function bta_ftc_hdl_event +** +** Description File transfer server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_ftc_hdl_event(BT_HDR *p_msg) +{ + tBTA_FTC_CB *p_cb = &bta_ftc_cb; +#if BTA_FTC_DEBUG == TRUE + tBTA_FTC_STATE in_state = p_cb->state; +#endif + + switch (p_msg->event) + { + case BTA_FTC_API_ENABLE_EVT: +#if BTA_FTC_DEBUG == TRUE + APPL_TRACE_DEBUG3("FTC Event Handler: State 0x%02x [%s], Event [%s]", in_state, + ftc_state_code(in_state), + ftc_evt_code(p_msg->event)); +#endif + bta_ftc_api_enable(p_cb, (tBTA_FTC_DATA *) p_msg); +#if BTA_FTC_DEBUG == TRUE + if (in_state != p_cb->state) + { + APPL_TRACE_DEBUG3("FTC State Change: [%s] -> [%s] after Event [%s]", + ftc_state_code(in_state), + ftc_state_code(p_cb->state), + ftc_evt_code(p_msg->event)); + } +#endif + break; + + default: + if (p_cb->is_enabled) + { + bta_ftc_sm_execute(p_cb, p_msg->event, (tBTA_FTC_DATA *) p_msg); + + if ( p_cb->state == BTA_FTC_CONN_ST ) + { + if (( p_cb->pm_state == BTA_FTC_PM_IDLE ) + &&( p_cb->obx_oper != FTC_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA FTC informs DM/PM busy state"); + bta_sys_busy( BTA_ID_FTC, p_cb->app_id, p_cb->bd_addr ); + p_cb->pm_state = BTA_FTC_PM_BUSY; + } + else if (( p_cb->pm_state == BTA_FTC_PM_BUSY ) + &&( p_cb->obx_oper == FTC_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA FTC informs DM/PM idle state"); + bta_sys_idle( BTA_ID_FTC ,p_cb->app_id, p_cb->bd_addr); + p_cb->pm_state = BTA_FTC_PM_IDLE; + } + } + else if ( p_cb->state == BTA_FTC_IDLE_ST ) + { + /* initialize power management state */ + p_cb->pm_state = BTA_FTC_PM_BUSY; + } + } + break; + } + + + return (TRUE); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_FTC_DEBUG == TRUE + +/******************************************************************************* +** +** Function ftc_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *ftc_evt_code(tBTA_FTC_INT_EVT evt_code) +{ + switch(evt_code) + { + case BTA_FTC_API_DISABLE_EVT: + return "BTA_FTC_API_DISABLE_EVT"; + case BTA_FTC_API_OPEN_EVT: + return "BTA_FTC_API_OPEN_EVT"; + case BTA_FTC_API_CLOSE_EVT: + return "BTA_FTC_API_CLOSE_EVT"; + case BTA_FTC_API_PUTFILE_EVT: + return "BTA_FTC_API_PUTFILE_EVT"; + case BTA_FTC_API_GETFILE_EVT: + return "BTA_FTC_API_GETFILE_EVT"; + case BTA_FTC_API_LISTDIR_EVT: + return "BTA_FTC_API_LISTDIR_EVT"; + case BTA_FTC_API_CHDIR_EVT: + return "BTA_FTC_API_CHDIR_EVT"; + case BTA_FTC_API_MKDIR_EVT: + return "BTA_FTC_API_MKDIR_EVT"; + case BTA_FTC_API_REMOVE_EVT: + return "BTA_FTC_API_REMOVE_EVT"; + case BTA_FTC_API_AUTHRSP_EVT: + return "BTA_FTC_API_AUTHRSP_EVT"; + case BTA_FTC_API_ABORT_EVT: + return "BTA_FTC_API_ABORT_EVT"; + case BTA_FTC_API_ACTION_EVT: + return "BTA_FTC_API_ACTION_EVT"; + case BTA_FTC_OBX_ACTION_RSP_EVT: + return "BTA_FTC_OBX_ACTION_RSP_EVT"; + case BTA_FTC_CI_SESSION_EVT: + return "BTA_FTC_CI_SESSION_EVT"; + case BTA_FTC_SDP_OK_EVT: + return "BTA_FTC_SDP_OK_EVT"; + case BTA_FTC_SDP_FAIL_EVT: + return "BTA_FTC_SDP_FAIL_EVT"; + case BTA_FTC_SDP_NEXT_EVT: + return "BTA_FTC_SDP_NEXT_EVT"; + case BTA_FTC_CI_WRITE_EVT: + return "BTA_FTC_CI_WRITE_EVT"; + case BTA_FTC_CI_READ_EVT: + return "BTA_FTC_CI_READ_EVT"; + case BTA_FTC_CI_OPEN_EVT: + return "BTA_FTC_CI_OPEN_EVT"; + case BTA_FTC_OBX_CONN_RSP_EVT: + return "BTA_FTC_OBX_CONN_RSP_EVT"; + case BTA_FTC_OBX_ABORT_RSP_EVT: + return "BTA_FTC_OBX_ABORT_RSP_EVT"; + case BTA_FTC_OBX_TOUT_EVT: + return "BTA_FTC_OBX_TOUT_EVT"; + case BTA_FTC_OBX_PASSWORD_EVT: + return "BTA_FTC_OBX_PASSWORD_EVT"; + case BTA_FTC_OBX_CLOSE_EVT: + return "BTA_FTC_OBX_CLOSE_EVT"; + case BTA_FTC_OBX_PUT_RSP_EVT: + return "BTA_FTC_OBX_PUT_RSP_EVT"; + case BTA_FTC_CLOSE_CMPL_EVT: + return "BTA_FTC_CLOSE_CMPL_EVT"; + case BTA_FTC_OBX_GET_RSP_EVT: + return "BTA_FTC_OBX_GET_RSP_EVT"; + case BTA_FTC_OBX_SETPATH_RSP_EVT: + return "BTA_FTC_OBX_SETPATH_RSP_EVT"; + case BTA_FTC_OBX_CMPL_EVT: + return "BTA_FTC_OBX_CMPL_EVT"; + case BTA_FTC_DISABLE_CMPL_EVT: + return "BTA_FTC_DISABLE_CMPL_EVT"; + case BTA_FTC_RSP_TOUT_EVT: + return "BTA_FTC_RSP_TOUT_EVT"; + case BTA_FTC_API_ENABLE_EVT: + return "BTA_FTC_API_ENABLE_EVT"; + default: + return "unknown FTC event code"; + } +} + +/******************************************************************************* +** +** Function ftc_state_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *ftc_state_code(tBTA_FTC_STATE state_code) +{ + switch(state_code) + { + case BTA_FTC_IDLE_ST: + return "BTA_FTC_IDLE_ST"; + case BTA_FTC_W4_CONN_ST: + return "BTA_FTC_W4_CONN_ST"; + case BTA_FTC_CONN_ST: + return "BTA_FTC_CONN_ST"; + case BTA_FTC_SUSPENDING_ST: + return "BTA_FTC_SUSPENDING_ST"; + case BTA_FTC_CLOSING_ST: + return "BTA_FTC_CLOSING_ST"; + default: + return "unknown FTC state code"; + } +} + +#endif /* Debug Functions */ +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_ftc_utils.c b/bta/ft/bta_ftc_utils.c new file mode 100644 index 0000000..8468d5f --- /dev/null +++ b/bta/ft/bta_ftc_utils.c @@ -0,0 +1,608 @@ +/***************************************************************************** +** +** Name: bta_ftc_utils.c +** +** Description: This file implements object store functions for the +** file transfer server. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include <stdio.h> +#include <string.h> +#include "bta_ftc_int.h" +#include "bta_fs_api.h" +#include "bta_fs_co.h" +#include "gki.h" +#include "utl.h" + +/******************************************************************************* +** Constants +*******************************************************************************/ + +/******************************************************************************* +** Local Function Prototypes +*******************************************************************************/ + +/******************************************************************************* +* Macros for FTC +*******************************************************************************/ +#define BTA_FTC_XML_EOL "\n" +#define BTA_FTC_FOLDER_LISTING_START ( "<?xml version=\"1.0\"?>\n" \ + "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">\n" \ + "<folder-listing version=\"1.0\">\n" ) + +#define BTA_FTC_FOLDER_LISTING_END ( "</folder-listing>" ) + +#define BTA_FTC_FILE_ELEM "file" +#define BTA_FTC_FOLDER_ELEM "folder" +#define BTA_FTC_PARENT_FOLDER_ELEM "parent-folder" +#define BTA_FTC_NAME_ATTR "name" +#define BTA_FTC_SIZE_ATTR "size" +#define BTA_FTC_TYPE_ATTR "type" +#define BTA_FTC_MODIFIED_ATTR "modified" +#define BTA_FTC_CREATED_ATTR "created" +#define BTA_FTC_ACCESSED_ATTR "accessed" +#define BTA_FTC_USER_PERM_ATTR "user-perm" +#define BTA_FTC_GROUP_PERM_ATTR "group-perm" +#define BTA_FTC_OTHER_PERM_ATTR "other-perm" +#define BTA_FTC_GROUP_ATTR "group" +#define BTA_FTC_OWNER_ATTR "owner" +#define BTA_FTC_LANG_ATTR "xml:lang" + +/******************************************************************************* +** Local Function +*******************************************************************************/ +/******************************************************************************* +** +** Function bta_ftc_send_abort_req +** +** Description Send an abort request. +** +** Parameters p_cb - Pointer to the FTC control block +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_send_abort_req(tBTA_FTC_CB *p_cb) +{ + if (FTC_ABORT_REQ_NOT_SENT == p_cb->aborting) + { + p_cb->aborting = FTC_ABORT_REQ_SENT; + OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL); + + /* Start abort response timer */ + p_cb->timer_oper = FTC_TIMER_OP_ABORT; + bta_sys_start_timer(&p_cb->rsp_timer, BTA_FTC_RSP_TOUT_EVT, + p_bta_ft_cfg->abort_tout); + } +} +/******************************************************************************* +** +** Function bta_ftc_proc_pbap_param +** +** Description read PBAP app parameter header. +** +** Parameters +** +** Returns +** +*******************************************************************************/ +tBTA_FTC_PB_PARAM * bta_ftc_proc_pbap_param(tBTA_FTC_PB_PARAM *p_param, BT_HDR *p_pkt) +{ + UINT8 *p_data = NULL, aph; + UINT16 data_len = 0; + int left, len; + if(OBX_ReadByteStrHdr(p_pkt, OBX_HI_APP_PARMS, &p_data, &data_len, 0)) + { + memset(p_param, 0, sizeof(tBTA_FTC_PB_PARAM)); + left = data_len; + while(left > 0) + { + aph = *p_data++; + len = *p_data++; + left -= len; + left -= 2; + switch(aph) + { + case BTA_FTC_APH_PB_SIZE: + BE_STREAM_TO_UINT16(p_param->phone_book_size, p_data); + p_param->pbs_exist = TRUE; + break; + case BTA_FTC_APH_NEW_MISSED_CALL: + p_param->new_missed_calls = *p_data++; + p_param->nmc_exist = TRUE; + break; + default: + p_data += len; + } + } + } + else + p_param = NULL; + return p_param; +} + +/******************************************************************************* +* Exported Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function bta_ftc_send_get_req +** +** Description Processes a Get File Operation. +** +** Parameters p_cb - Pointer to the FTC control block +** +** Returns (UINT8) OBX response code +** +*******************************************************************************/ +UINT8 bta_ftc_send_get_req(tBTA_FTC_CB *p_cb) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + UINT8 rsp_code = OBX_RSP_FAILED; + + /* Do not start another request if currently aborting */ + if (!p_cb->aborting) + { + /* OBX header are added in bta_ftc_init_getfile */ + if ((OBX_GetReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS) + { + p_cb->req_pending = TRUE; + rsp_code = OBX_RSP_OK; + p_obx->p_pkt = NULL; + } + } + else + { + bta_ftc_send_abort_req(p_cb); + } + + return (rsp_code); +} + +/******************************************************************************* +** +** Function bta_ftc_proc_get_rsp +** +** Description Processes a Get File response packet. +** Initiates a file write if no errors. +** +** Parameters +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_proc_get_rsp(tBTA_FTC_CB *p_cb, tBTA_FTC_DATA *p_data) +{ + tBTA_FTC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + UINT16 body_size; + BOOLEAN final; + BOOLEAN done = TRUE; + BOOLEAN send_request = TRUE; + UINT8 num_hdrs; + tBTA_FTC data; + + do + { + if (p_evt->rsp_code == OBX_RSP_OK || p_evt->rsp_code == OBX_RSP_CONTINUE) + { + /* Only continue if not aborting */ + if (p_cb->aborting) + { + /* Aborting: done with current packet */ + utl_freebuf((void**)&p_evt->p_pkt); + + /* If aborting, and this response is not last packet send abort */ + if(p_evt->rsp_code == OBX_RSP_CONTINUE) + { + bta_ftc_send_abort_req(p_cb); + return; + } + else /* Last packet - abort and remove file (p_evt->rsp_code == OBX_RSP_OK) */ + { + p_evt->rsp_code = (!p_cb->int_abort) ? OBX_RSP_GONE : OBX_RSP_INTRNL_SRVR_ERR; + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + return; + } + } + + p_obx->final_pkt = (p_evt->rsp_code == OBX_RSP_OK) ? TRUE : FALSE; + + /* If length header exists, save the file length */ + if (p_cb->first_req_pkt == TRUE) + { + p_cb->first_req_pkt = FALSE; + + /* if the obj_type is */ + if(p_cb->obj_type == BTA_FTC_GET_PB) + { + bta_ftc_proc_pbap_param(&data.pb, p_obx->p_pkt); + bta_ftc_cb.p_cback(BTA_FTC_PHONEBOOK_EVT, &data); + if (p_cb->fd == BTA_FS_INVALID_FD) + { + /* if the obj_type is get pb && the file id not open, + * must be getting the phonebook size only + * - end of transaction */ + break; + } + } + if (!OBX_ReadLengthHdr(p_evt->p_pkt, &p_cb->file_size)) + p_cb->file_size = BTA_FS_LEN_UNKNOWN; + } + + /* Read the body header from the obx packet */ + num_hdrs = OBX_ReadBodyHdr(p_evt->p_pkt, &p_obx->p_start, &body_size, + &final); + /* process body header */ + if (num_hdrs == 1) + { + if (body_size) + { + /* Data to be written */ + p_obx->p_pkt = p_evt->p_pkt; + p_obx->offset = body_size; /* Save write size for comparison */ + p_cb->cout_active = TRUE; + bta_fs_co_write(p_cb->fd, p_obx->p_start, body_size, + BTA_FTC_CI_WRITE_EVT, 0, p_cb->app_id); + done = FALSE; + send_request = FALSE; + } + /* If body header is zero in length but not final, request next packet */ + else if (!final) + { + done = FALSE; + } + } + else if (num_hdrs > 1) /* Cannot handle more than a single body header */ + { + p_evt->rsp_code = OBX_RSP_BAD_REQUEST; + } + /* Empty Body; send next request or finished */ + else if (!p_obx->final_pkt) + done = FALSE; + } + } while (0); + + if (done) + { + bta_ftc_sm_execute(p_cb, BTA_FTC_OBX_CMPL_EVT, p_data); + utl_freebuf((void**)&p_evt->p_pkt); + } + else if (send_request) + { + /* Free current packet and send a new request */ + utl_freebuf((void**)&p_evt->p_pkt); + bta_ftc_send_get_req(p_cb); + } +} + +/******************************************************************************* +** +** Function bta_ftc_cont_put_file +** +** Description Continues a Put File Operation. +** Builds a new OBX packet, and initiates a read operation. +** +** Parameters p_cb - pointer to the client's control block. +** first_pkt - TRUE if initial PUT request to server. +** +** +** Returns UINT8 OBX response code +** +*******************************************************************************/ +UINT8 bta_ftc_cont_put_file(tBTA_FTC_CB *p_cb, BOOLEAN first_pkt) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + UINT8 rsp_code; + char *p_ch; + + /* Do not start another request if currently aborting */ + if (p_cb->aborting) + { + bta_ftc_send_abort_req(p_cb); + return (OBX_RSP_OK); + } + + rsp_code = OBX_RSP_FAILED; + + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu)) != NULL) + { + p_obx->offset = 0; + + /* Add length header if it exists; No body in first packet */ + if (first_pkt) + { + /* Add the Name Header to the request */ + /* Find the beginning of the name (excluding the path) */ + p_ch = strrchr(p_cb->p_name, (int) p_bta_fs_cfg->path_separator); + if (p_ch && p_ch[1] != '\0') + { + OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)&p_ch[1]); + + /* Add the length header if known */ + if (p_cb->file_size != BTA_FS_LEN_UNKNOWN) + { + OBX_AddLengthHdr(p_obx->p_pkt, p_cb->file_size); + + } + + OBX_PutReq(p_cb->obx_handle, FALSE, p_obx->p_pkt); + p_cb->req_pending = TRUE; + p_obx->p_pkt = NULL; + rsp_code = OBX_RSP_OK; + } + } + else /* A continuation packet so read file data */ + { + /* Add the start of the Body Header */ + p_obx->bytes_left = 0; + p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left); + + /* Read in the first packet's worth of data */ + p_cb->cout_active = TRUE; + bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset], + p_obx->bytes_left, BTA_FTC_CI_READ_EVT, 0, p_cb->app_id); + rsp_code = OBX_RSP_OK; + } + } + + return (rsp_code); +} + +/******************************************************************************* +** +** Function bta_ftc_proc_list_data +** +** Description Processes responses to directory listing requests +** Loops through returned data generating application +** listing data events. If needed, issues a new request +** to the server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_proc_list_data(tBTA_FTC_CB *p_cb, tBTA_FTC_OBX_EVT *p_evt) +{ + tBTA_FTC app_evt; + tBTA_FTC_PB_PARAM param; + BOOLEAN is_ok = FALSE; + BOOLEAN first_req_pkt = p_cb->first_req_pkt; + + app_evt.list.status = bta_ftc_convert_obx_to_ftc_status(p_evt->rsp_code); + + if (p_evt->rsp_code == OBX_RSP_OK || p_evt->rsp_code == OBX_RSP_CONTINUE) + { + app_evt.list.p_param = NULL; + if (p_cb->first_req_pkt == TRUE) + { + p_cb->first_req_pkt = FALSE; + if(p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) + app_evt.list.p_param = bta_ftc_proc_pbap_param(¶m, p_evt->p_pkt); + } + APPL_TRACE_EVENT1("first_req_pkt: %d ", first_req_pkt); + + if (OBX_ReadBodyHdr(p_evt->p_pkt, &app_evt.list.data, &app_evt.list.len, + &app_evt.list.final)) + { + /* len > 0 or is final packet */ + if(app_evt.list.len || app_evt.list.final) + + { + bta_ftc_cb.p_cback(BTA_FTC_LIST_EVT, &app_evt); + } + is_ok = TRUE; + } + else if(first_req_pkt && p_evt->rsp_code == OBX_RSP_CONTINUE) + { + /* no body header is OK, if this is the first packet and is continue response */ + is_ok = TRUE; + } + + if(is_ok) + { + utl_freebuf((void**)&p_evt->p_pkt); + /* Initiate another request if not finished */ + if (p_evt->rsp_code == OBX_RSP_CONTINUE) + { + if (p_cb->aborting) + bta_ftc_send_abort_req(p_cb); + else + bta_ftc_get_listing(p_cb, NULL, NULL); + } + else + p_cb->obx_oper = FTC_OP_NONE; /* Finished with directory listing */ + } + else + { + /* Missing body header & not the first packet */ + bta_ftc_listing_err(&p_evt->p_pkt, OBX_RSP_NO_CONTENT); + } + } + else /* Issue an error list entry */ + bta_ftc_listing_err(&p_evt->p_pkt, app_evt.list.status); +} + +/******************************************************************************* +** +** Function bta_ftc_get_listing +** +** Description Initiates or Continues a GET Listing operation +** on the server's current directory. +** +** Parameters p_cb - pointer to the client's control block. +** first_pkt - TRUE if initial GET request to server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_get_listing(tBTA_FTC_CB *p_cb, char *p_name, tBTA_FTC_LST_PARAM *p_param) +{ + tBTA_FTC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTC_STATUS status = BTA_FTC_FAIL; + BOOLEAN is_ok = TRUE; + UINT8 *p, *p2, *p_start; + UINT16 len = 0; + + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_CMD_POOL_SIZE)) != NULL) + { + if (p_name) + { + /* first packet */ + p_cb->first_req_pkt = TRUE; + /* Add the Type Header */ + p = (UINT8 *) BTA_FTC_FOLDER_LISTING_TYPE; + if(p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) + p = (UINT8 *) BTA_FTC_PULL_VCARD_LISTING_TYPE; + + is_ok = OBX_AddTypeHdr(p_obx->p_pkt, (char *)p); + + if(strcmp(p_name, ".") == 0 || p_name[0] == 0) + { + p_name = NULL; + } + + if (p_name) + { + is_ok = OBX_AddUtf8NameHdr(p_obx->p_pkt, (unsigned char *) p_name); + } + + if(p_param && p_cb->sdp_service == UUID_SERVCLASS_PBAP_PSE) + { + /* add app params for PCE */ + p_start = OBX_AddByteStrStart(p_obx->p_pkt, &len); + p = p_start; + if(p_param->order < BTA_FTC_ORDER_MAX) + { + *p++ = BTA_FTC_APH_ORDER; + *p++ = 1; + *p++ = p_param->order; + } + if(p_param->p_value) + { + *p++ = BTA_FTC_APH_SEARCH_VALUE; + *p = strlen(p_param->p_value); + BCM_STRNCPY_S((char *) (p+1), strlen(p_param->p_value), p_param->p_value, *p); + p2 = p + 1 + *p; + p = p2; + } + if(p_param->attribute < BTA_FTC_ATTR_MAX) + { + *p++ = BTA_FTC_APH_SEARCH_ATTR; + *p++ = 1; + *p++ = p_param->attribute; + } + if(p_param->max_list_count != 0xFFFF) + { + *p++ = BTA_FTC_APH_MAX_LIST_COUNT; + *p++ = 2; + UINT16_TO_BE_STREAM(p, p_param->max_list_count); + } + if(p_param->list_start_offset) + { + *p++ = BTA_FTC_APH_LIST_STOFF; + *p++ = 2; + UINT16_TO_BE_STREAM(p, p_param->list_start_offset); + } + + /* If any of the app param header is added */ + if(p != p_start) + { + OBX_AddByteStrHdr(p_obx->p_pkt, OBX_HI_APP_PARMS, NULL, (UINT16)(p - p_start)); + } + } /* if p_param: PBAP PCE need to keep AppParam in the first Get response */ + } + + if (is_ok) + { + if ((OBX_GetReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS) + { + p_cb->req_pending = TRUE; + p_obx->p_pkt = NULL; /* OBX will free the memory */ + p_cb->obx_oper = FTC_OP_GET_LIST; + status = BTA_FTC_OK; + } + } + } + + if (status != BTA_FTC_OK) /* Send an error response to the application */ + bta_ftc_listing_err(&p_obx->p_pkt, status); +} + +/******************************************************************************* +** +** Function bta_ftc_listing_err +** +** Description Send a directory listing error event to the application +** +** Returns void +** +*******************************************************************************/ +void bta_ftc_listing_err(BT_HDR **p_pkt, tBTA_FTC_STATUS status) +{ + tBTA_FTC err_rsp; + + if (bta_ftc_cb.obx_oper == FTC_OP_GET_LIST) + bta_ftc_cb.obx_oper = FTC_OP_NONE; + utl_freebuf((void**)p_pkt); + + err_rsp.list.len = 0; + err_rsp.list.status = status; + err_rsp.list.final = TRUE; + err_rsp.list.data = NULL; + bta_ftc_cb.p_cback(BTA_FTC_LIST_EVT, &err_rsp); +} + +/******************************************************************************* +** +** Function bta_ftc_convert_obx_to_ftc_status +** +** Description Convert OBX response code into BTA FTC status code. +** +** Returns void +** +*******************************************************************************/ +tBTA_FTC_STATUS bta_ftc_convert_obx_to_ftc_status(tOBX_STATUS obx_status) +{ + tBTA_FTC_STATUS status; + + switch (obx_status) + { + case OBX_RSP_OK: + case OBX_RSP_CONTINUE: + status = BTA_FTC_OK; + break; + case OBX_RSP_UNAUTHORIZED: + status = BTA_FTC_NO_PERMISSION; + break; + case OBX_RSP_NOT_FOUND: + status = BTA_FTC_NOT_FOUND; + break; + case OBX_RSP_REQ_ENT_2_LARGE: + case OBX_RSP_DATABASE_FULL: + status = BTA_FTC_FULL; + break; + case OBX_RSP_GONE: + status = BTA_FTC_ABORTED; + break; + case OBX_RSP_SERVICE_UNAVL: + status = BTA_FTC_SERVICE_UNAVL; + break; + default: + status = BTA_FTC_FAIL; + } + + return (status); +} +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_fts_act.c b/bta/ft/bta_fts_act.c new file mode 100644 index 0000000..52ba9e4 --- /dev/null +++ b/bta/ft/bta_fts_act.c @@ -0,0 +1,1523 @@ +/***************************************************************************** +** +** Name: bta_fts_act.c +** +** Description: This file contains the file transfer action +** functions for the state machine. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include <stdio.h> +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_ft_api.h" +#include "bta_fts_int.h" +#include "bta_fs_api.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#include "btm_api.h" +#include "utl.h" +#include "bd.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +#define FLAGS_ARE_MASK (OBX_SPF_BACKUP | OBX_SPF_NO_CREATE) +#define FLAGS_ARE_ILLEGAL 0x1 /* 'Backup and Create flag combo is BAD */ + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +#if BTA_FTS_DEBUG == TRUE +static char *fts_obx_evt_code(tOBX_EVENT evt_code); +#endif + +/***************************************************************************** +** Action Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_fts_api_disable +** +** Description Stop FTP server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_api_disable(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + + /* If callout is active, wait till finished before shutting down */ + if (p_cb->cout_active) + p_cb->disabling = TRUE; + else + bta_fts_sm_execute(p_cb, BTA_FTS_DISABLE_CMPL_EVT, p_data); + + bta_sys_remove_uuid(UUID_SERVCLASS_OBEX_FILE_TRANSFER); + BTM_SecClrService(BTM_SEC_SERVICE_OBEX_FTP); +} + +/******************************************************************************* +** +** Function bta_fts_api_authrsp +** +** Description Pass the response to an authentication request back to the +** client. +** +** Returns void +** +*******************************************************************************/ +void bta_fts_api_authrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + UINT8 *p_pwd = NULL; + UINT8 *p_userid = NULL; + + if (p_data->auth_rsp.key_len > 0) + p_pwd = (UINT8 *)p_data->auth_rsp.key; + if (p_data->auth_rsp.userid_len > 0) + p_userid = (UINT8 *)p_data->auth_rsp.userid; + + OBX_Password(p_cb->obx_handle, p_pwd, p_data->auth_rsp.key_len, + p_userid, p_data->auth_rsp.userid_len); +} + +/******************************************************************************* +** +** Function bta_fts_api_accessrsp +** +** Description Process the access API event. +** If permission had been granted, continue the PUT operation, +** otherwise stop the operation. +** +** Returns void +** +*******************************************************************************/ +void bta_fts_api_accessrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + UINT8 rsp_code = OBX_RSP_OK; + tBTA_FS_CO_STATUS status = BTA_FS_CO_EACCES; + tBTA_FT_ACCESS access = p_data->access_rsp.flag; + tBTA_FT_OPER old_acc_active = p_cb->acc_active; + tBTA_FTS_OBX_RSP *p_rsp = NULL; + tBTA_FTS_OBJECT objevt; + + APPL_TRACE_DEBUG3("bta_fts_api_accessrsp op:%d/%d access:%d", old_acc_active, p_data->access_rsp.oper, access); + if(p_cb->acc_active != p_data->access_rsp.oper ) + { + APPL_TRACE_WARNING2("FTS ACCRSP: not match active:%d, rsp:%d", + p_cb->acc_active, p_data->access_rsp.oper); + return; + } + + p_cb->acc_active = 0; + /* Process the currently active access response */ + switch (old_acc_active) + { + case BTA_FT_OPER_PUT: + if (access == BTA_FT_ACCESS_ALLOW) + { + /* Save the file name with path prepended */ + BCM_STRNCPY_S(p_cb->p_path, p_bta_fs_cfg->max_file_len+1, p_data->access_rsp.p_name, p_bta_fs_cfg->max_file_len); + p_cb->p_path[p_bta_fs_cfg->max_file_len] = '\0'; + + p_cb->cout_active = TRUE; + bta_fs_co_open (p_cb->p_path, + (BTA_FS_O_CREAT | BTA_FS_O_TRUNC | BTA_FS_O_RDWR), + p_cb->file_length, BTA_FTS_CI_OPEN_EVT, + p_cb->app_id); + } + else /* Access denied */ + { + bta_fts_clean_getput(p_cb, TRUE); + OBX_PutRsp(p_cb->obx_handle, OBX_RSP_UNAUTHORIZED, (BT_HDR *)NULL); + } + break; + + case BTA_FT_OPER_GET: + if (access == BTA_FT_ACCESS_ALLOW) + { + p_cb->cout_active = TRUE; + bta_fs_co_open (p_cb->p_path, BTA_FS_O_RDONLY, 0, + BTA_FTS_CI_OPEN_EVT, p_cb->app_id); + } + else /* Denied */ + bta_fts_get_file_rsp(OBX_RSP_UNAUTHORIZED, 0); + break; + + case BTA_FT_OPER_DEL_FILE: /* Request is a DELETE file */ + p_rsp = OBX_PutRsp; + if (access == BTA_FT_ACCESS_ALLOW) + { + objevt.p_name = p_cb->p_path; + objevt.status = BTA_FTS_OK; + if ((status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id)) != BTA_FS_CO_OK) + { + objevt.status = BTA_FTS_FAIL; + } + + /* Notify application of delete attempt */ + p_cb->p_cback(BTA_FTS_DEL_CMPL_EVT, (tBTA_FTS *)&objevt); + } + break; + + case BTA_FT_OPER_DEL_DIR: /* Request is a DELETE folder */ + p_rsp = OBX_PutRsp; + if (access == BTA_FT_ACCESS_ALLOW) + { + objevt.p_name = p_cb->p_path; + objevt.status = BTA_FTS_OK; + if ((status = bta_fs_co_rmdir(p_cb->p_path, p_cb->app_id)) != BTA_FS_CO_OK) + { + objevt.status = BTA_FTS_FAIL; + } + + /* Notify application of delete attempt */ + p_cb->p_cback(BTA_FTS_DEL_CMPL_EVT, (tBTA_FTS *)&objevt); + } + break; + + case BTA_FT_OPER_CHG_DIR: /* Request is a Change Folder */ + p_rsp = OBX_SetPathRsp; + if (access == BTA_FT_ACCESS_ALLOW) + { + status = BTA_FS_CO_OK; + BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_path, p_bta_fs_cfg->max_path_len); + p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0'; + APPL_TRACE_DEBUG1("FTS: SET NEW PATH [%s]", p_cb->p_workdir); + bta_fs_co_setdir(p_cb->p_workdir, p_cb->app_id); + } + break; + + case BTA_FT_OPER_MK_DIR: /* Request is a Make Folder */ + p_rsp = OBX_SetPathRsp; + if (access == BTA_FT_ACCESS_ALLOW) + { + if ((status = bta_fs_co_mkdir(p_cb->p_path, p_cb->app_id)) == BTA_FS_CO_OK) + { + BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_path, p_bta_fs_cfg->max_path_len); + p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0'; + APPL_TRACE_DEBUG1("FTS: SET NEW PATH [%s]", p_cb->p_workdir); + bta_fs_co_setdir(p_cb->p_workdir, p_cb->app_id); + } + } + break; + + case BTA_FT_OPER_COPY_ACT: + if (access == BTA_FT_ACCESS_ALLOW) + { + p_cb->cout_active = TRUE; + bta_fs_co_copy(p_cb->p_path, p_cb->p_dest, p_cb->perms, BTA_FTS_CI_OPEN_EVT, p_cb->app_id); + } + else + p_rsp = OBX_ActionRsp; + break; + + case BTA_FT_OPER_MOVE_ACT: + if (access == BTA_FT_ACCESS_ALLOW) + { + p_cb->cout_active = TRUE; + bta_fs_co_rename(p_cb->p_path, p_cb->p_dest, p_cb->perms, BTA_FTS_CI_OPEN_EVT, p_cb->app_id); + } + else + p_rsp = OBX_ActionRsp; + break; + + case BTA_FT_OPER_SET_PERM: + if (access == BTA_FT_ACCESS_ALLOW) + { + p_cb->cout_active = TRUE; + bta_fs_co_set_perms(p_cb->p_path, p_cb->perms, BTA_FTS_CI_OPEN_EVT, p_cb->app_id); + } + else + p_rsp = OBX_ActionRsp; + break; + + default: + p_cb->acc_active = old_acc_active; + APPL_TRACE_WARNING1("FTS ACCRSP: Unknown tBTA_FT_OPER value (%d)", + p_cb->acc_active); + } + if(p_rsp) + { + switch (status) + { + case BTA_FS_CO_OK: + rsp_code = OBX_RSP_OK; + break; + case BTA_FS_CO_ENOTEMPTY: + rsp_code = OBX_RSP_PRECONDTN_FAILED; + break; + case BTA_FS_CO_EACCES: + rsp_code = OBX_RSP_UNAUTHORIZED; + break; + default: + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + utl_freebuf((void**)&p_cb->p_name); + utl_freebuf((void**)&p_cb->p_path); + utl_freebuf((void**)&p_cb->p_dest); + + p_cb->obx_oper = FTS_OP_NONE; + (*p_rsp)(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_fts_api_close +** +** Description Handle an api close event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_api_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + BD_ADDR bd_addr; + if (OBX_GetPeerAddr(p_cb->obx_handle, bd_addr) != 0) + { + /* resources will be freed at BTA_PBS_OBX_CLOSE_EVT */ + OBX_DisconnectRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, NULL); + } + else + { + p_cb->p_cback(BTA_FTS_CLOSE_EVT, 0); + } +} + +/******************************************************************************* +** +** Function bta_fts_ci_write +** +** Description Continue with the current write operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_ci_write(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + p_cb->cout_active = FALSE; + + if (p_cb->disabling) + { + bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data); + } + + /* Process write call-in event if operation is still active */ + if (p_cb->obx_oper == FTS_OP_PUT_FILE) + { + if (p_data->write_evt.status == BTA_FS_CO_OK) + rsp_code = OBX_RSP_OK; + else + { + if (p_data->write_evt.status == BTA_FS_CO_ENOSPACE) + rsp_code = OBX_RSP_DATABASE_FULL; + bta_fts_clean_getput(p_cb, TRUE); + } + + /* Process response to OBX client */ + bta_fts_put_file_rsp(rsp_code); + } +} + +/******************************************************************************* +** +** Function bta_fts_ci_read +** +** Description Handles the response to a read call-out request. +** This is called within the OBX get file request. If the +** operation has completed, the OBX response is sent out; +** otherwise a read for additional data is made. +** +** Returns void +** +*******************************************************************************/ +void bta_fts_ci_read(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt; + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + p_cb->cout_active = FALSE; + + if (p_cb->disabling) + { + bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data); + } + + /* Process read call-in event if operation is still active */ + if (p_cb->obx_oper == FTS_OP_GET_FILE && p_revt->fd == p_cb->fd) + { + /* Read was successful, not finished yet */ + if (p_revt->status == BTA_FS_CO_OK) + rsp_code = OBX_RSP_CONTINUE; + + /* Read was successful, end of file has been detected */ + else if (p_revt->status == BTA_FS_CO_EOF) + rsp_code = OBX_RSP_OK; + + /* Process response to OBX client */ + bta_fts_get_file_rsp(rsp_code, p_revt->num_read); + } +} + +/******************************************************************************* +** +** Function bta_fts_ci_resume +** +** Description Continue with the current file open operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_ci_resume(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_UTL_COD cod; + + p_cb->state = BTA_FTS_LISTEN_ST; + APPL_TRACE_EVENT1("bta_fts_ci_resume status:%d", p_data->resume_evt.status); + /* Set the File Transfer service class bit */ + cod.service = BTM_COD_SERVICE_OBJ_TRANSFER; + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); + if (p_data->resume_evt.status == BTA_FS_CO_OK) + { + OBX_AddSuspendedSession (p_cb->obx_handle, p_data->resume_evt.p_addr, + p_data->resume_evt.p_sess_info, p_data->resume_evt.timeout, + p_data->resume_evt.ssn, p_data->resume_evt.offset); + } +} + +/******************************************************************************* +** +** Function bta_fts_ci_open +** +** Description Continue with the current file open operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_ci_open(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt; + UINT8 rsp_code = OBX_RSP_OK; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + UINT8 num_hdrs; + BOOLEAN endpkt; + + p_cb->cout_active = FALSE; + + if (p_cb->disabling) + { + bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data); + } + + /* If using OBEX 1.5 */ + if ( p_cb->obx_oper & FTS_OP_RESUME) + { + /* clear the FTS_OP_RESUME when the first request is received. + * We may need to adjust ssn/offset */ + if ((p_open->fd >= 0) && (p_cb->obx_oper == FTS_OP_RESUME)) + { + /* file is open successfully when the resumed obex op is FTS_OP_NONE + * close this file */ + bta_fs_co_close(p_open->fd, p_cb->app_id); + p_open->fd = BTA_FS_INVALID_FD; + } + p_cb->fd = p_open->fd; + return; + } + + /* Only process file get or put operations */ + if (p_cb->obx_oper == FTS_OP_GET_FILE) + { + /* if file is accessible read/write the first buffer of data */ + if (p_open->status == BTA_FS_CO_OK) + { + p_cb->file_length = p_open->file_size; + p_cb->fd = p_open->fd; + + /* Add the length header if available */ + if (p_cb->file_length != BTA_FS_LEN_UNKNOWN) + { + OBX_AddLengthHdr(p_obx->p_pkt, p_cb->file_length); + if (p_cb->file_length > 0) + rsp_code = OBX_RSP_CONTINUE; + else + OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE); + } + + /* Send continuation response with the length of the file and no body */ + OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt); + p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */ + + if (p_cb->file_length == 0) + bta_fts_clean_getput(p_cb, FALSE); + } + else + { + if (p_open->status == BTA_FS_CO_EACCES) + rsp_code = OBX_RSP_UNAUTHORIZED; + else /* File could not be found */ + rsp_code = OBX_RSP_NOT_FOUND; + + /* Send OBX response if an error occurred */ + bta_fts_get_file_rsp(rsp_code, 0); + } + } + else if (p_cb->obx_oper == FTS_OP_PUT_FILE) + { + /* if file is accessible read/write the first buffer of data */ + if (p_open->status == BTA_FS_CO_OK) + { + p_cb->fd = p_open->fd; + + /* Read in start of body if there is a body header */ + num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start, + &p_obx->bytes_left, &endpkt); + if (num_hdrs == 1) + { + rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */ + /* Initiate the writing out of the data */ + p_cb->cout_active = TRUE; + bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset], + p_obx->bytes_left, BTA_FTS_CI_WRITE_EVT, 0, + p_cb->app_id); + } + else if (num_hdrs > 1) /* Cannot handle multiple body headers */ + { + rsp_code = OBX_RSP_BAD_REQUEST; + bta_fts_clean_getput(p_cb, TRUE); + } + else /* No body: respond with an OK so client can start sending the data */ + p_obx->bytes_left = 0; + + if (rsp_code != OBX_RSP_PART_CONTENT) + { + bta_fts_put_file_rsp(rsp_code); + } + } + else + { + if (p_open->status == BTA_FS_CO_EACCES) + rsp_code = OBX_RSP_UNAUTHORIZED; + else if (p_open->status == BTA_FS_CO_ENOSPACE) + rsp_code = OBX_RSP_DATABASE_FULL; + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + /* Send OBX response now if an error occurred */ + bta_fts_put_file_rsp(rsp_code); + } + } + /* If using OBEX 1.5 */ + else + { + /* must be action commands BTA_FT_OPER_COPY_ACT - BTA_FT_OPER_SET_PERM*/ + switch (p_open->status) + { + case BTA_FS_CO_OK: + rsp_code = OBX_RSP_OK; + break; + case BTA_FS_CO_EACCES: + rsp_code = OBX_RSP_UNAUTHORIZED; + break; + case BTA_FS_CO_EIS_DIR: + rsp_code = OBX_RSP_FORBIDDEN; + default: + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + utl_freebuf((void**)&p_cb->p_name); + utl_freebuf((void**)&p_cb->p_path); + utl_freebuf((void**)&p_cb->p_dest); + p_cb->obx_oper = FTS_OP_NONE; + OBX_ActionRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_fts_ci_direntry +** +** Description Continue getting the current directory entry operation +** +** Returns void +** +*******************************************************************************/ +void bta_fts_ci_direntry(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + UINT8 rsp_code; + BOOLEAN free_pkt = TRUE; + + p_cb->cout_active = FALSE; + + if (p_cb->disabling) + { + bta_fts_sm_execute(p_cb,BTA_FTS_DISABLE_CMPL_EVT, p_data); + } + + /* Process dirent listing call-in event if operation is still active */ + if (p_cb->obx_oper == FTS_OP_LISTING) + { + switch (p_data->getdir_evt.status) + { + case BTA_FS_CO_OK: /* Valid new entry */ + free_pkt = FALSE; + if ((rsp_code = bta_fts_add_list_entry()) != OBX_RSP_PART_CONTENT) + bta_fts_end_of_list(rsp_code); + break; + + case BTA_FS_CO_EODIR: /* End of list (entry not valid) */ + free_pkt = FALSE; + bta_fts_end_of_list(OBX_RSP_OK); + break; + + case BTA_FS_CO_FAIL: /* Error occurred */ + bta_fts_end_of_list(OBX_RSP_NOT_FOUND); + break; + } + } + + if (free_pkt) + utl_freebuf((void **)&p_cb->obx.p_pkt); +} + +/******************************************************************************* +** +** Function bta_fts_obx_connect +** +** Description Process the OBX connect event +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_connect(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess; + + APPL_TRACE_DEBUG1("bta_fts_obx_connect obx_event=%d", p_evt->obx_event); + if (p_evt->obx_event == OBX_SESSION_REQ_EVT) + { + APPL_TRACE_EVENT3("sess_op:%d obj_offset:x%x ssn:%d", p_sess->sess_op, p_sess->obj_offset, p_sess->ssn); + + BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len); + p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0'; + + bta_fs_co_session_info(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn, + BTA_FS_CO_SESS_ST_ACTIVE, p_cb->p_workdir, &p_cb->obx_oper, p_cb->app_id); + APPL_TRACE_DEBUG1("obx_oper:%d", p_cb->obx_oper); + if (p_sess->sess_op == OBX_SESS_OP_CREATE) + { + p_cb->state = BTA_FTS_LISTEN_ST; + p_cb->obx_oper = FTS_OP_NONE; + } + else if (p_sess->sess_op == OBX_SESS_OP_RESUME) + { + p_cb->state = BTA_FTS_LISTEN_ST; + p_cb->resume_ssn = p_sess->ssn; + APPL_TRACE_EVENT1("resume ssn:%d", p_sess->ssn); + if (p_cb->obx_oper) + { + bta_fs_co_resume_op(p_sess->obj_offset, BTA_FTS_CI_OPEN_EVT, p_cb->app_id); + p_cb->obx_oper |= FTS_OP_RESUME; + } + } + return; + } + + p_cb->peer_mtu = p_evt->param.conn.mtu; + memcpy(p_cb->bd_addr, p_evt->param.conn.peer_addr, BD_ADDR_LEN); + APPL_TRACE_EVENT2("FTS Connect: peer mtu 0x%04x handle:0x%x", p_cb->peer_mtu, p_evt->handle); + + if (!p_evt->param.conn.no_rsp) + { + OBX_ConnectRsp(p_evt->handle, OBX_RSP_OK, (BT_HDR *)NULL); + + /* Reset to the root directory */ + BCM_STRNCPY_S(p_cb->p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len); + p_cb->p_workdir[p_bta_fs_cfg->max_path_len] = '\0'; + + bta_fs_co_setdir(p_cb->p_workdir, p_cb->app_id); + } + + /* inform role manager */ + bta_sys_conn_open( BTA_ID_FTS, p_cb->app_id, p_cb->bd_addr); + + /* Notify the MMI that a connection has been opened */ + p_cb->p_cback(BTA_FTS_OPEN_EVT, (tBTA_FTS*)p_cb->bd_addr); + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/******************************************************************************* +** +** Function bta_fts_obx_disc +** +** Description Process the OBX disconnect event +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_disc(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code; + + rsp_code = (p_evt->obx_event == OBX_DISCONNECT_REQ_EVT) ? OBX_RSP_OK + : OBX_RSP_BAD_REQUEST; + OBX_DisconnectRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/******************************************************************************* +** +** Function bta_fts_obx_close +** +** Description Process the OBX link lost event +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + /* finished if not waiting on a call-in function */ + if (!p_cb->cout_active) + bta_fts_sm_execute(p_cb, BTA_FTS_CLOSE_CMPL_EVT, p_data); +} + +/******************************************************************************* +** +** Function bta_fts_obx_abort +** +** Description Process the OBX abort event +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_abort(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_OK; + + utl_freebuf((void**)&p_evt->p_pkt); + + switch (p_cb->obx_oper) + { + case FTS_OP_LISTING: + utl_freebuf((void**)&p_cb->obx.p_pkt); + bta_fts_clean_list(p_cb); + break; + + case FTS_OP_GET_FILE: + case FTS_OP_PUT_FILE: + bta_fts_clean_getput(p_cb, TRUE); + break; + + default: /* Reply OK to the client */ + rsp_code = OBX_RSP_BAD_REQUEST; + } + + OBX_AbortRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); +} + +/******************************************************************************* +** +** Function bta_fts_obx_password +** +** Description Process the OBX password request +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_password(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + tBTA_FTS_AUTH *p_auth; + BOOLEAN is_challenged; + tOBX_AUTH_OPT options; + + if ((p_auth = (tBTA_FTS_AUTH *)GKI_getbuf(sizeof(tBTA_FTS_AUTH))) != NULL) + { + memset(p_auth, 0, sizeof(tBTA_FTS_AUTH)); + + /* Extract user id from packet (if available) */ + if (OBX_ReadAuthParams(p_data->obx_evt.p_pkt, &p_auth->p_userid, + &p_auth->userid_len, + &is_challenged, &options)) + { + if (options & OBX_AO_USR_ID) + p_auth->userid_required = TRUE; + } + + /* Don't need OBX packet any longer */ + utl_freebuf((void**)&p_evt->p_pkt); + + /* Notify application */ + p_cb->p_cback(BTA_FTS_AUTH_EVT, (tBTA_FTS *)p_auth); + + GKI_freebuf(p_auth); + } +} + +/******************************************************************************* +** +** Function bta_fts_obx_put +** +** Description Process the OBX file put and delete file/folder events +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_put(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_OK; + BOOLEAN rsp_now = TRUE; + BOOLEAN free_in_pkt = TRUE; + UINT8 obx_oper = bta_fts_cb.obx_oper; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + UINT8 num_hdrs; + BOOLEAN endpkt; + + APPL_TRACE_EVENT1("bta_fts_obx_put oper=x%x", p_cb->obx_oper); + + /* If using OBEX 1.5 */ + if ( p_cb->obx_oper & FTS_OP_RESUME) + { + APPL_TRACE_EVENT2("bta_fts_obx_put ssn:%d resume ssn:%d", p_evt->param.get.ssn, p_cb->resume_ssn); + p_cb->obx_oper &= ~FTS_OP_RESUME; + num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start, + &p_obx->bytes_left, &endpkt); + if ((p_evt->param.get.ssn != p_cb->resume_ssn) && (p_cb->fd >= 0)) + { + if ((p_cb->obx_oper == FTS_OP_PUT_FILE) && (num_hdrs == 0) && ((p_evt->param.get.ssn + 1) == p_cb->resume_ssn)) + { + APPL_TRACE_EVENT0("client did not get the last PUT response. Just want another response pkt"); + } + else + bta_fs_co_sess_ssn(p_cb->fd, p_evt->param.put.ssn, p_cb->app_id); + } + } + + /* If currently processing a PUT, use the current name */ + if (bta_fts_cb.obx_oper == FTS_OP_PUT_FILE) + { + free_in_pkt = FALSE; /* Hang on to Obx packet until done */ + bta_fts_proc_put_file(p_evt->p_pkt, p_cb->p_name, p_evt->param.put.final, obx_oper); + rsp_now = FALSE; /* Response sent after processing the request */ + } + else /* This is a new request */ + { + /* Pull out the name header if it exists */ + if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1))) != NULL) + { + if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *) p_cb->p_name, p_bta_fs_cfg->max_file_len)) + { + /* Is Put operation Delete, Create, or Put */ + if (p_evt->param.put.type == OBX_PT_DELETE) + { + APPL_TRACE_EVENT1("FTS File/Folder Delete: Name [%s]", p_cb->p_name); + bta_fts_delete(p_evt, p_cb->p_name); + utl_freebuf((void**)&p_cb->p_name); + } + else /* File Put or File Create */ + { + free_in_pkt = FALSE; /* Hang on to Obx packet until done */ + APPL_TRACE_EVENT1("FTS File Put: Name [%s]", p_cb->p_name); + bta_fts_proc_put_file(p_evt->p_pkt, p_cb->p_name, p_evt->param.put.final, obx_oper); + } + + rsp_now = FALSE; /* Response sent after processing the request */ + } + else /* Must have a name header */ + { + utl_freebuf((void**)&p_cb->p_name); + rsp_code = OBX_RSP_BAD_REQUEST; + } + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + + /* Respond right away if an error has been detected processing request */ + if (rsp_now) + OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + + /* Done with Obex packet */ + if (free_in_pkt) + utl_freebuf((void**)&p_evt->p_pkt); + +} + +/******************************************************************************* +** +** Function bta_fts_obx_get +** +** Description Process the OBX file get and folder listing events +** If the type header is not folder listing, then pulling a file. +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_get(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT16 len; + BOOLEAN is_file_get = TRUE; /* Set to false if folder listing */ + UINT8 *p_type; + + APPL_TRACE_EVENT1("bta_fts_obx_get:%d", bta_fts_cb.obx_oper); + + /* If using OBEX 1.5 */ + if ( p_cb->obx_oper & FTS_OP_RESUME) + { + p_cb->obx_oper &= ~FTS_OP_RESUME; + APPL_TRACE_DEBUG3("ssn:%d resume ssn:%d, op:%d", p_evt->param.get.ssn, p_cb->resume_ssn, bta_fts_cb.obx_oper ); + if (bta_fts_cb.obx_oper == FTS_OP_LISTING) + { + /* abort the listing */ + bta_fts_end_of_list(OBX_RSP_INTRNL_SRVR_ERR); + return; + } + else if ((p_evt->param.get.ssn != p_cb->resume_ssn) && (p_cb->fd >= 0)) + { + APPL_TRACE_EVENT2("ssn:%d resume ssn:%d", p_evt->param.get.ssn, p_cb->resume_ssn); + bta_fs_co_sess_ssn(p_cb->fd, p_evt->param.get.ssn, p_cb->app_id); + } + } + + /* If currently processing a GET, use the current name */ + if (bta_fts_cb.obx_oper == FTS_OP_LISTING) + bta_fts_getdirlist(p_cb->p_name); + else if (bta_fts_cb.obx_oper == FTS_OP_GET_FILE) + bta_fts_proc_get_file(p_cb->p_name); + + else /* This is a new request */ + { + /* Pull out the name header if it exists */ + if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1))) != NULL) + { + if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len)) + { + GKI_freebuf(p_cb->p_name); + p_cb->p_name = NULL; + } + } + + /* See if getting a folder listing */ + if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len)) + { + if (!memcmp(p_type, BTA_FTS_FOLDER_LISTING_TYPE, len)) + { + is_file_get = FALSE; + bta_fts_getdirlist(p_cb->p_name); + } + } + + /* Initiate the Get File request if not folder listing */ + if (is_file_get) + { + if (p_cb->p_name) + { + APPL_TRACE_EVENT1("FTS File Get: Name [%s]", p_cb->p_name); + } + bta_fts_proc_get_file(p_cb->p_name); + } + } + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/******************************************************************************* +** +** Function bta_fts_obx_setpath +** +** Description Process the FTP change or make directory requests +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_setpath(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_BAD_REQUEST; + tOBX_SETPATH_FLAG *p_flag = &p_evt->param.sp.flag; + tBTA_FT_OPER ft_op = 0; + + /* Verify flags and handle before accepting */ + if (p_evt->handle == p_cb->obx_handle && + (((*p_flag) & FLAGS_ARE_MASK) != FLAGS_ARE_ILLEGAL)) + { + p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1)); + p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + + p_bta_fs_cfg->max_file_len + 2)); + if (p_cb->p_name != NULL && p_cb->p_path != NULL) + { + if (!OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len)) + { + utl_freebuf((void **)&p_cb->p_name); /* no name header */ + } + else if (!p_cb->p_name) + { + /* empty name header set to null terminated string */ + p_cb->p_name[0] = '\0'; + } + + + /* Determine if operation is mkdir */ + if (!((*p_flag) & OBX_SPF_NO_CREATE)) + { + rsp_code = bta_fts_mkdir(p_evt->p_pkt, &ft_op); + + /* If the directory already exists, silently perform change directory */ + if(rsp_code == OBX_RSP_CONTINUE) + { + /* Note BACKUP flag must be FALSE for mkdir operation */ + rsp_code = bta_fts_chdir(p_evt->p_pkt, FALSE, &ft_op); + } + } + else /* Operation is chdir */ + rsp_code = bta_fts_chdir(p_evt->p_pkt, (BOOLEAN)((*p_flag) & OBX_SPF_BACKUP), &ft_op); + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + + if (ft_op) + { + bta_fts_req_app_access(ft_op, p_cb); + } + else + { + OBX_SetPathRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + utl_freebuf((void**)&p_cb->p_name); + utl_freebuf((void**)&p_cb->p_path); + } + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/* Using OBEX 1.5 */ +/******************************************************************************* +** +** Function bta_fts_obx_action +** +** Description Process the FTP action requests +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_action(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_BAD_REQUEST; + tBTA_FT_OPER ft_op = 0; + UINT8 action; + BOOLEAN is_dir; + BOOLEAN has_perms = FALSE; + char *p_dest_name = NULL; + char *p_newpath = NULL; + + /* Verify flags and handle before accepting */ + if (p_evt->handle == p_cb->obx_handle ) + { + if (OBX_ReadActionIdHdr(p_evt->p_pkt, &action)) + { + p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1)); + p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + + p_bta_fs_cfg->max_file_len + 2)); + p_newpath = p_cb->p_path; + if ((p_cb->p_name != NULL) && (p_cb->p_path != NULL) && + ((strlen(p_cb->p_name) + strlen(p_cb->p_workdir) + 1) <= p_bta_fs_cfg->max_path_len)) + + { + if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len) && + p_cb->p_name[0]) + { + /* the packet has non-empty name header */ + sprintf(p_newpath, "%s%c%s", p_cb->p_workdir, + p_bta_fs_cfg->path_separator, p_cb->p_name); + if (((bta_fs_co_access(p_newpath, BTA_FS_ACC_EXIST, + &is_dir, p_cb->app_id)) == BTA_FS_CO_OK)) + { + /* the src object exists */ + ft_op = BTA_FT_OPER_COPY_ACT + action; + } + else + rsp_code = OBX_RSP_NOT_FOUND; + } + + if (ft_op) + { + memset (p_cb->perms, 0, BTA_FS_PERM_SIZE); + /* it's SetPermission -> need Permission Header */ + if (OBX_ReadPermissionHdr(p_evt->p_pkt, &p_cb->perms[BTA_FS_PERM_USER], + &p_cb->perms[BTA_FS_PERM_GROUP], &p_cb->perms[BTA_FS_PERM_OTHER])) + { + has_perms = TRUE; + } + if (action != BTA_FT_ACT_PERMISSION) + { + /* it's Move or Copy -> need DestName Header */ + p_dest_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + 1)); + p_cb->p_dest = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + + p_bta_fs_cfg->max_file_len + 2)); + p_newpath = p_cb->p_dest; + if (p_dest_name && p_cb->p_dest) + { + if (OBX_ReadUtf8DestNameHdr(p_evt->p_pkt, (UINT8 *)p_dest_name, p_bta_fs_cfg->max_file_len) && + p_dest_name[0]) + { + if (p_dest_name[0] == '/' || p_dest_name[0] == '\\') + { + /* the packet has non-empty DestName header */ + sprintf(p_newpath, "%s%c%s", p_cb->p_rootpath, + p_bta_fs_cfg->path_separator, p_dest_name); + } + else + { + /* the packet has non-empty DestName header */ + sprintf(p_newpath, "%s%c%s", p_cb->p_workdir, + p_bta_fs_cfg->path_separator, p_dest_name); + } + if (((bta_fs_co_access(p_newpath, BTA_FS_ACC_EXIST, + &is_dir, p_cb->app_id)) == BTA_FS_CO_FAIL)) + { + /* the dest object does not exist */ + rsp_code = OBX_RSP_OK; + } + } + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + else if (has_perms) + { + /* the SetPermission action must have the permission header */ + rsp_code = OBX_RSP_OK; + } + } + + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + } + + if(rsp_code == OBX_RSP_OK) + { + bta_fts_req_app_access(ft_op, p_cb); + } + else + { + OBX_ActionRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + utl_freebuf((void**)&p_cb->p_name); + utl_freebuf((void**)&p_cb->p_path); + utl_freebuf((void**)&p_dest_name); + utl_freebuf((void**)&p_cb->p_dest); + } + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} +/* end of using OBEX 1.5 */ + +/******************************************************************************* +** +** Function bta_fts_appl_tout +** +** Description Process the FTS application timeout event +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_appl_tout(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ +} + +/******************************************************************************* +** +** Function bta_fts_conn_err_rsp +** +** Description Process the OBX error response +** Connect request received in wrong state, or bad request +** from client +** +** Returns void +** +*******************************************************************************/ +void bta_fts_conn_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + OBX_ConnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL); +} + +/* Using OBEX 1.5 */ +/******************************************************************************* +** +** Function bta_fts_session_req +** +** Description Process the OBX session req in connected state +** +** Returns void +** +*******************************************************************************/ +void bta_fts_session_req(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + tOBX_SESS_EVT *p_sess = &p_data->obx_evt.param.sess; + UINT8 rsp_code = OBX_RSP_OK; + UINT32 offset = 0; + + if (p_evt->obx_event == OBX_SESSION_REQ_EVT) + { + APPL_TRACE_EVENT2("sess_op:%d ssn:%d", p_sess->sess_op, p_sess->ssn); + switch (p_sess->sess_op) + { + case OBX_SESS_OP_SUSPEND: + bta_fs_co_suspend(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn, &p_sess->timeout, &offset, p_cb->obx_oper, p_cb->app_id); + p_cb->state = BTA_FTS_CLOSING_ST; + p_cb->suspending = TRUE; + break; + + case OBX_SESS_OP_CLOSE: + bta_fs_co_session_info(p_cb->bd_addr, p_sess->p_sess_info, 0, BTA_FS_CO_SESS_ST_NONE, NULL, NULL, p_cb->app_id); + p_cb->state = BTA_FTS_CLOSING_ST; + break; + + case OBX_SESS_OP_CREATE: + case OBX_SESS_OP_RESUME: + p_cb->state = BTA_FTS_CONN_ST; + rsp_code = OBX_RSP_FORBIDDEN; + break; + } + OBX_SessionRsp (p_evt->handle, rsp_code, p_sess->ssn, offset, NULL); + return; + } + else if (p_evt->obx_event == OBX_SESSION_INFO_EVT) + { + if ((p_cb->obx_oper != FTS_OP_GET_FILE) && (p_cb->obx_oper != FTS_OP_PUT_FILE) && (p_cb->obx_oper != FTS_OP_LISTING)) + { + /* the other obx ops are single transaction. + * If the link is dropped before the transaction ends, let the client re-transmit the request */ + p_sess->ssn--; + p_cb->obx_oper = FTS_OP_NONE; + } + bta_fs_co_suspend(p_cb->bd_addr, p_sess->p_sess_info, p_sess->ssn, + &p_sess->timeout, &offset, p_cb->obx_oper, p_cb->app_id); + OBX_AddSuspendedSession (p_cb->obx_handle, p_cb->bd_addr, + p_sess->p_sess_info, p_sess->timeout, + p_sess->ssn, offset); + p_cb->suspending = TRUE; + } + else + { + p_cb->state = BTA_FTS_CONN_ST; + bta_fts_conn_err_rsp (p_cb, p_data); + } +} +/* End of using OBEX 1.5 */ + +/******************************************************************************* +** +** Function bta_fts_disc_err_rsp +** +** Description Process the OBX error response +** Disconnect request received in wrong state, or bad request +** from client +** +** Returns void +** +*******************************************************************************/ +void bta_fts_disc_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + OBX_DisconnectRsp(p_data->obx_evt.handle, OBX_RSP_BAD_REQUEST, (BT_HDR *)NULL); +} + +/******************************************************************************* +** +** Function bta_fts_gasp_err_rsp +** +** Description Process the OBX error response for Get, Abort, Setpath, and Put. +** +** The rsp_code field of tBTA_FTS_DATA (obx_evt) contains the +** response code to be sent to OBEX, and the obx_event field +** contains the current OBEX event. +** +** Returns void +** +*******************************************************************************/ +void bta_fts_gasp_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_OBX_EVENT *p_evt = &p_data->obx_evt; + tBTA_FTS_OBX_RSP *p_rsp = NULL; + + switch (p_evt->obx_event) + { + case OBX_PUT_REQ_EVT: + p_rsp = OBX_PutRsp; + break; + case OBX_GET_REQ_EVT: + p_rsp = OBX_GetRsp; + break; + case OBX_SETPATH_REQ_EVT: + p_rsp = OBX_SetPathRsp; + break; + case OBX_ABORT_REQ_EVT: + p_rsp = OBX_AbortRsp; + break; + case OBX_ACTION_REQ_EVT: + p_rsp = OBX_ActionRsp; + break; + } + if(p_rsp) + (*p_rsp)(p_evt->handle, p_evt->rsp_code, (BT_HDR *)NULL); +} + +/******************************************************************************* +** +** Function bta_fts_close_complete +** +** Description Finishes the memory cleanup after a channel is closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_close_complete(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + p_cb->cout_active = FALSE; + bta_fts_clean_getput(p_cb, TRUE); + bta_fts_clean_list(p_cb); + + /* inform role manager */ + bta_sys_conn_close( BTA_ID_FTS ,p_cb->app_id, p_cb->bd_addr); + + + + + /* Notify the MMI that a connection has been closed */ + p_cb->p_cback(BTA_FTS_CLOSE_EVT, (tBTA_FTS*)p_cb->bd_addr); + memset(p_cb->bd_addr, 0, BD_ADDR_LEN); + + if (p_data->obx_evt.p_pkt) + APPL_TRACE_WARNING0("FTS: OBX CLOSE CALLED WITH non-NULL Packet!!!"); +} + +/******************************************************************************* +** +** Function bta_fts_disable_cmpl +** +** Description Finishes the memory cleanup before shutting down server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_disable_cmpl(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + bta_fts_disable_cleanup(p_cb); +} + +/***************************************************************************** +** Callback Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_fts_obx_cback +** +** Description OBX callback function. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, + tOBX_EVT_PARAM param, BT_HDR *p_pkt) +{ + tBTA_FTS_OBX_EVENT *p_obx_msg; + UINT16 event = 0; + UINT16 size = sizeof(tBTA_FTS_OBX_EVENT); + +#if BTA_FTS_DEBUG == TRUE + APPL_TRACE_DEBUG2("OBX Event Callback: obx_event [%s] %d", fts_obx_evt_code(obx_event), obx_event); +#endif + + switch(obx_event) + { + case OBX_SESSION_INFO_EVT: /* the session information event to resume the session. */ + size += OBX_SESSION_INFO_SIZE; + /* Falls through */ + + case OBX_SESSION_REQ_EVT: + case OBX_CONNECT_REQ_EVT: + event = BTA_FTS_OBX_CONN_EVT; + break; + case OBX_ACTION_REQ_EVT: + event = BTA_FTS_OBX_ACTION_EVT; + break; + case OBX_DISCONNECT_REQ_EVT: + event = BTA_FTS_OBX_DISC_EVT; + break; + case OBX_PUT_REQ_EVT: + event = BTA_FTS_OBX_PUT_EVT; + break; + case OBX_GET_REQ_EVT: + event = BTA_FTS_OBX_GET_EVT; + break; + case OBX_SETPATH_REQ_EVT: + event = BTA_FTS_OBX_SETPATH_EVT; + break; + case OBX_ABORT_REQ_EVT: + event = BTA_FTS_OBX_ABORT_EVT; + break; + case OBX_CLOSE_IND_EVT: + event = BTA_FTS_OBX_CLOSE_EVT; + break; + case OBX_TIMEOUT_EVT: + break; + case OBX_PASSWORD_EVT: + event = BTA_FTS_OBX_PASSWORD_EVT; + break; + default: + /* Unrecognized packet; disconnect the session */ + if (p_pkt) + event = BTA_FTS_OBX_DISC_EVT; + } + + /* send event to BTA, if any */ + if (event && (p_obx_msg = + (tBTA_FTS_OBX_EVENT *) GKI_getbuf(size)) != NULL) + { + p_obx_msg->hdr.event = event; + p_obx_msg->obx_event = obx_event; + p_obx_msg->handle = handle; + p_obx_msg->param = param; + p_obx_msg->p_pkt = p_pkt; + + if (obx_event == OBX_SESSION_INFO_EVT) + { + p_obx_msg->param.sess.p_sess_info = (UINT8 *)(p_obx_msg + 1); + memcpy (p_obx_msg->param.sess.p_sess_info, param.sess.p_sess_info, OBX_SESSION_INFO_SIZE); + } + + bta_sys_sendmsg(p_obx_msg); + } +} + +/***************************************************************************** +** Local FTP Event Processing Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_fts_req_app_access +** +** Description Sends an access request event to the application. +** +** Returns void +** +*******************************************************************************/ +void bta_fts_req_app_access (tBTA_FT_OPER oper, tBTA_FTS_CB *p_cb) +{ + tBTA_FTS_ACCESS *p_acc_evt; + char *p_devname; + + /* Notify the application that a put or get file has been requested */ + if ((p_acc_evt = (tBTA_FTS_ACCESS *)GKI_getbuf(sizeof(tBTA_FTS_ACCESS))) != NULL) + { + memset(p_acc_evt, 0, sizeof(tBTA_FTS_ACCESS)); + + APPL_TRACE_API1("ACCESS REQ: [%s]", p_cb->p_path); + + p_acc_evt->p_name = p_cb->p_path; + p_acc_evt->p_dest_name = p_cb->p_dest; + memcpy(p_acc_evt->perms, p_cb->perms, BTA_FS_PERM_SIZE); + + p_acc_evt->size = p_cb->file_length; + p_acc_evt->oper = p_cb->acc_active = oper; + bdcpy(p_acc_evt->bd_addr, p_cb->bd_addr); + if ((p_devname = BTM_SecReadDevName(p_cb->bd_addr)) != NULL) + BCM_STRNCPY_S((char *)p_acc_evt->dev_name, sizeof(p_acc_evt->dev_name), p_devname, BTM_MAX_REM_BD_NAME_LEN); + + p_cb->p_cback(BTA_FTS_ACCESS_EVT, (tBTA_FTS *)p_acc_evt); + GKI_freebuf(p_acc_evt); + } +} + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_FTS_DEBUG == TRUE + +/******************************************************************************* +** +** Function fts_obx_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *fts_obx_evt_code(tOBX_EVENT evt_code) +{ + switch(evt_code) + { + case OBX_CONNECT_REQ_EVT: + return "OBX_CONNECT_REQ_EVT"; + case OBX_DISCONNECT_REQ_EVT: + return "OBX_DISCONNECT_REQ_EVT"; + case OBX_PUT_REQ_EVT: + return "OBX_PUT_REQ_EVT"; + case OBX_GET_REQ_EVT: + return "OBX_GET_REQ_EVT"; + case OBX_SETPATH_REQ_EVT: + return "OBX_SETPATH_REQ_EVT"; + case OBX_ABORT_REQ_EVT: + return "OBX_ABORT_REQ_EVT"; + case OBX_CLOSE_IND_EVT: + return "OBX_CLOSE_IND_EVT"; + case OBX_TIMEOUT_EVT: + return "OBX_TIMEOUT_EVT"; + case OBX_PASSWORD_EVT: + return "OBX_PASSWORD_EVT"; + case OBX_SESSION_REQ_EVT: + return "OBX_SESSION_REQ_EVT"; + case OBX_ACTION_REQ_EVT: + return "OBX_ACTION_REQ_EVT"; + case OBX_SESSION_INFO_EVT: + return "OBX_SESSION_INFO_EVT"; + + default: + return "unknown OBX event code"; + } +} +#endif /* Debug Functions */ +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_fts_api.c b/bta/ft/bta_fts_api.c new file mode 100644 index 0000000..be359e0 --- /dev/null +++ b/bta/ft/bta_fts_api.c @@ -0,0 +1,230 @@ +/***************************************************************************** +** +** Name: bta_fts_api.c +** +** Description: This is the implementation of the API for the file +** transfer server subsystem of BTA, Widcomm's Bluetooth +** application layer for mobile phones. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_fs_api.h" +#include "bta_fts_int.h" + +// btla-specific ++ +//todo sdh + +/* Maximum path length supported by MMI */ +#ifndef BTA_FS_PATH_LEN +#define BTA_FS_PATH_LEN 294 +#endif +// btla-specific -- + + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_fts_reg = +{ + bta_fts_hdl_event, + BTA_FtsDisable +}; + +/******************************************************************************* +** +** Function BTA_FtsEnable +** +** Description Enable the file transfer server. This function must be +** called before any other functions in the FTS API are called. +** When the enable operation is complete the callback function +** will be called with an BTA_FTS_ENABLE_EVT event. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_FtsEnable(tBTA_SEC sec_mask, const char *p_service_name, + const char *p_root_path, BOOLEAN enable_authen, + UINT8 realm_len, UINT8 *p_realm, + tBTA_FTS_CBACK *p_cback, UINT8 app_id) +{ + tBTA_FTS_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_FTS, &bta_fts_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_FTS_API_ENABLE *)GKI_getbuf((UINT16)(sizeof(tBTA_FTS_API_ENABLE) + + p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_FTS_API_ENABLE)); + + p_buf->p_root_path = (char *)(p_buf + 1); + p_buf->p_root_path[p_bta_fs_cfg->max_path_len] = '\0'; + + p_buf->hdr.event = BTA_FTS_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->sec_mask = sec_mask; + p_buf->app_id = app_id; + p_buf->auth_enabled = enable_authen; + + p_buf->realm_len = (realm_len < OBX_MAX_REALM_LEN) ? realm_len : + OBX_MAX_REALM_LEN; + if (p_realm) + memcpy(p_buf->realm, p_realm, p_buf->realm_len); + + if (p_service_name) + BCM_STRNCPY_S(p_buf->servicename, sizeof(p_buf->servicename), p_service_name, BTA_SERVICE_NAME_LEN); + + if (p_root_path) + { + BCM_STRNCPY_S(p_buf->p_root_path, p_bta_fs_cfg->max_path_len+1, p_root_path, + p_bta_fs_cfg->max_path_len); + p_buf->p_root_path[p_bta_fs_cfg->max_path_len] = '\0'; + } + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtsDisable +** +** Description Disable the file transfer server. If the server is currently +** connected to a peer device the connection will be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtsDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_FTS); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_FTS_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtsClose +** +** Description Close the current connection. This function is called if +** the phone wishes to close the connection before the FT +** client disconnects. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_FtsClose(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_FTS_API_CLOSE_EVT; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_FtsUnauthRsp +** +** Description Sends an OBEX authentication challenge to the connected +** OBEX client. Called in response to an BTA_FTS_AUTH_EVT event. +** Used when "enable_authen" is set to TRUE in BTA_FtsEnable(). +** +** Note: If the "userid_required" is TRUE in the BTA_FTS_AUTH_EVT +** event, then p_userid is required, otherwise it is optional. +** +** p_password must be less than BTA_FTS_MAX_AUTH_KEY_SIZE +** p_userid must be less than OBX_MAX_REALM_LEN +** +** Returns void +** +*******************************************************************************/ +void BTA_FtsAuthRsp (char *p_password, char *p_userid) +{ + tBTA_FTS_API_AUTHRSP *p_auth_rsp; + + if ((p_auth_rsp = (tBTA_FTS_API_AUTHRSP *)GKI_getbuf(sizeof(tBTA_FTS_API_AUTHRSP))) != NULL) + { + memset(p_auth_rsp, 0, sizeof(tBTA_FTS_API_AUTHRSP)); + + p_auth_rsp->hdr.event = BTA_FTS_API_AUTHRSP_EVT; + + if (p_password) + { + p_auth_rsp->key_len = strlen(p_password); + if (p_auth_rsp->key_len > BTA_FTS_MAX_AUTH_KEY_SIZE) + p_auth_rsp->key_len = BTA_FTS_MAX_AUTH_KEY_SIZE; + memcpy(p_auth_rsp->key, p_password, p_auth_rsp->key_len); + } + + if (p_userid) + { + p_auth_rsp->userid_len = strlen(p_userid); + if (p_auth_rsp->userid_len > OBX_MAX_REALM_LEN) + p_auth_rsp->userid_len = OBX_MAX_REALM_LEN; + memcpy(p_auth_rsp->userid, p_userid, p_auth_rsp->userid_len); + } + + bta_sys_sendmsg(p_auth_rsp); + } +} + +/******************************************************************************* +** +** Function BTA_FtsAccessRsp +** +** Description Sends a reply to an access request event (BTA_FTS_ACCESS_EVT). +** This call MUST be made whenever the event occurs. +** +** Parameters oper - operation being accessed. +** access - BTA_FT_ACCESS_ALLOW or BTA_FT_ACCESS_FORBID +** p_name - Full path of file to pulled or pushed. +** +** Returns void +** +*******************************************************************************/ +void BTA_FtsAccessRsp(tBTA_FT_OPER oper, tBTA_FT_ACCESS access, char *p_name) +{ + tBTA_FTS_API_ACCESSRSP *p_acc_rsp; + + if ((p_acc_rsp = (tBTA_FTS_API_ACCESSRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_FTS_API_ACCESSRSP) + + p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + p_acc_rsp->flag = access; + p_acc_rsp->oper = oper; + p_acc_rsp->p_name = (char *)(p_acc_rsp + 1); + if (p_name) + { + BCM_STRNCPY_S(p_acc_rsp->p_name, BTA_FS_PATH_LEN, p_name, p_bta_fs_cfg->max_path_len-1); + p_acc_rsp->p_name[p_bta_fs_cfg->max_path_len-1] = '\0'; + } + else + *p_acc_rsp->p_name = '\0'; + + p_acc_rsp->hdr.event = BTA_FTS_API_ACCESSRSP_EVT; + bta_sys_sendmsg(p_acc_rsp); + } +} +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_fts_int.h b/bta/ft/bta_fts_int.h new file mode 100644 index 0000000..b77c96f --- /dev/null +++ b/bta/ft/bta_fts_int.h @@ -0,0 +1,287 @@ +/***************************************************************************** +** +** Name: bta_fts_int.h +** +** Description: This is the private file for the file transfer +** server (FTS). +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_FTS_INT_H +#define BTA_FTS_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_ft_api.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#include "bta_ftc_int.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + + + +#define BTA_FTS_FOLDER_BROWSING_TARGET_UUID "\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09" +#define BTA_FTS_UUID_LENGTH 16 +#define BTA_FTS_MAX_AUTH_KEY_SIZE 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */ + +#define BTA_FTS_DEFAULT_VERSION 0x0100 +#define BTA_FTS_FOLDER_LISTING_TYPE "x-obex/folder-listing" + +typedef tOBX_STATUS (tBTA_FTS_OBX_RSP) (tOBX_HANDLE handle, UINT8 rsp_code, BT_HDR *p_pkt); + +/* FTS Active ftp obex operation (Valid in connected state) */ +#define FTS_OP_NONE 0 +#define FTS_OP_LISTING 1 +#define FTS_OP_GET_FILE 2 +#define FTS_OP_PUT_FILE 3 +#define FTS_OP_DELETE 4 /* Folder or File */ +#define FTS_OP_CHDIR 5 +#define FTS_OP_MKDIR 6 +#define FTS_OP_RESUME 0x10 + +/* state machine states */ +enum +{ + BTA_FTS_IDLE_ST = 0, /* Idle */ + BTA_FTS_LISTEN_ST, /* Listen - waiting for OBX/RFC connection */ + BTA_FTS_W4_AUTH_ST, /* Wait for Authentication - (optional) */ + BTA_FTS_CONN_ST, /* Connected - FTP Session is active */ + BTA_FTS_CLOSING_ST /* Closing is in progress */ +}; + +/* state machine events */ +enum +{ + /* these events are handled by the state machine */ + BTA_FTS_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_FTS), + + BTA_FTS_API_AUTHRSP_EVT, /* Response to password request */ + BTA_FTS_API_ACCESSRSP_EVT, /* Response to an access request */ + BTA_FTS_API_CLOSE_EVT, /* Disconnect the OBEX channel */ + BTA_FTS_CI_WRITE_EVT, /* Response to Write request */ + BTA_FTS_CI_READ_EVT, /* Response to Read request */ + BTA_FTS_CI_OPEN_EVT, /* Response to File Open request */ + BTA_FTS_CI_DIRENTRY_EVT, /* Response to a directory entry request */ + BTA_FTS_OBX_CONN_EVT, /* OBX Channel Connect Request */ + BTA_FTS_OBX_DISC_EVT, /* OBX Channel Disconnect */ + BTA_FTS_OBX_ABORT_EVT, /* OBX_operation aborted */ + BTA_FTS_OBX_PASSWORD_EVT, /* OBX password requested */ + BTA_FTS_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */ + BTA_FTS_OBX_PUT_EVT, /* Write file data or delete */ + BTA_FTS_OBX_GET_EVT, /* Read file data or folder listing */ + BTA_FTS_OBX_SETPATH_EVT, /* Make or Change Directory */ + BTA_FTS_CI_SESSION_EVT, /* Call-in response to session requests */ + BTA_FTS_OBX_ACTION_EVT, /* Action command */ + BTA_FTS_APPL_TOUT_EVT, /* Timeout waiting for application */ + BTA_FTS_DISC_ERR_EVT, /* Sends OBX_DisconnectRsp with error code */ + BTA_FTS_GASP_ERR_EVT, /* Sends Err Resp to Get, Abort, Setpath, and Put */ + BTA_FTS_CLOSE_CMPL_EVT, /* Finished closing channel */ + BTA_FTS_DISABLE_CMPL_EVT, /* Finished disabling server */ + + /* these events are handled outside the state machine */ + BTA_FTS_API_ENABLE_EVT +}; + +typedef UINT16 tBTA_FTS_INT_EVT; + +typedef UINT8 tBTA_FTS_STATE; + +/* data type for BTA_FTS_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_FTS_CBACK *p_cback; + char servicename[BTA_SERVICE_NAME_LEN + 1]; + char *p_root_path; + UINT8 realm [OBX_MAX_REALM_LEN]; /* The realm is intended to be + displayed to users so they know + which userid and password to use. + The first byte of the string is + the character set of the string. + */ + UINT8 realm_len; + UINT8 sec_mask; + UINT8 app_id; + BOOLEAN auth_enabled; +} tBTA_FTS_API_ENABLE; + +/* data type for BTA_FTS_API_AUTHRSP_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 key [BTA_FTS_MAX_AUTH_KEY_SIZE]; /* The authentication key.*/ + UINT8 key_len; + UINT8 userid [OBX_MAX_REALM_LEN]; /* The authentication user id.*/ + UINT8 userid_len; +} tBTA_FTS_API_AUTHRSP; + +/* data type for BTA_FTS_API_ACCESSRSP_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_name; + tBTA_FT_OPER oper; + tBTA_FT_ACCESS flag; +} tBTA_FTS_API_ACCESSRSP; + +/* data type for all obex events + hdr.event contains the FTS event +*/ +typedef struct +{ + BT_HDR hdr; + tOBX_HANDLE handle; + tOBX_EVT_PARAM param; + BT_HDR *p_pkt; + tOBX_EVENT obx_event; + UINT8 rsp_code; +} tBTA_FTS_OBX_EVENT; + +/* union of all event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_FTS_API_ENABLE api_enable; + tBTA_FTS_API_AUTHRSP auth_rsp; + tBTA_FTS_API_ACCESSRSP access_rsp; + tBTA_FTS_OBX_EVENT obx_evt; + tBTA_FS_CI_GETDIR_EVT getdir_evt; + tBTA_FS_CI_OPEN_EVT open_evt; + tBTA_FS_CI_RESUME_EVT resume_evt; + tBTA_FS_CI_READ_EVT read_evt; + tBTA_FS_CI_WRITE_EVT write_evt; +} tBTA_FTS_DATA; + + +/* OBX Response Packet Structure - Holds current response packet info */ +typedef struct +{ + BT_HDR *p_pkt; /* (Get/Put) Holds the current OBX header for Put or Get */ + UINT8 *p_start; /* (Get/Put) Start of the Body of the packet */ + UINT16 offset; /* (Get/Put) Contains the current offset into the Body (p_start) */ + UINT16 bytes_left; /* (Get/Put) Holds bytes available left in Obx packet */ + BOOLEAN final_pkt; /* (Put) Holds the final bit of the Put packet */ +} tBTA_FTS_OBX_PKT; + +/* Directory Listing Information */ +typedef struct +{ + tBTA_FS_DIRENTRY *p_entry; /* Holds current directory entry */ + BOOLEAN is_root; /* TRUE if path is root directory */ +} tBTA_FTS_DIRLIST; + +/* Power management state for FTS */ +#define BTA_FTS_PM_BUSY 0 +#define BTA_FTS_PM_IDLE 1 + +/* FTS control block */ +typedef struct +{ + tBTA_FTS_CBACK *p_cback; /* pointer to application callback function */ + char *p_name; /* Holds name of current operation */ + char *p_dest; /* Holds p_dest_name of current operation */ + char *p_path; /* Holds path of current operation */ + char *p_rootpath; + char *p_workdir; /* Current working directory */ + tBTA_FTS_OBX_PKT obx; /* Holds the current OBX packet information */ + tBTA_FTS_DIRLIST dir; /* Holds current directory list information */ + UINT32 sdp_handle; /* SDP record handle */ + UINT32 file_length; /* length of file being PUT/GET */ + UINT8 sess_id[OBX_SESSION_ID_SIZE]; /* session id */ + int fd; /* File Descriptor of opened file */ + BD_ADDR bd_addr; /* Device currently connected to */ + tOBX_HANDLE obx_handle; + UINT16 peer_mtu; + UINT16 psm; /* PSM for Obex Over L2CAP */ + UINT8 perms[BTA_FS_PERM_SIZE]; /* the permission */ + UINT8 scn; /* SCN of the FTP server */ + tBTA_FTS_STATE state; /* state machine state */ + UINT8 obx_oper; /* current active OBX operation PUT FILE, GET FILE, LISTING, etc */ + UINT8 app_id; + BOOLEAN auth_enabled; /* Is OBEX authentication enabled */ + BOOLEAN cout_active; /* TRUE when waiting for a call-in function */ + tBTA_FT_OPER acc_active; /* op code when waiting for an access rsp (API) (0 not active) */ + BOOLEAN suspending; /* TRUE when suspending session */ + UINT8 resume_ssn; /* the ssn for resume session */ + BOOLEAN disabling; /* TRUE when disabling server */ + UINT8 pm_state; /* power management state */ +} tBTA_FTS_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* FTS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_FTS_CB bta_fts_cb; +#else +extern tBTA_FTS_CB *bta_fts_cb_ptr; +#define bta_fts_cb (*bta_fts_cb_ptr) +#endif + +/* FT configuration constants */ +extern tBTA_FT_CFG * p_bta_ft_cfg; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +extern BOOLEAN bta_fts_hdl_event(BT_HDR *p_msg); +extern void bta_fts_sm_execute(tBTA_FTS_CB *p_cb, UINT16 event, tBTA_FTS_DATA *p_data); +extern void bta_fts_sdp_register (tBTA_FTS_CB *p_cb, char *p_service_name); +extern void bta_fts_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event, + tOBX_EVT_PARAM param, BT_HDR *p_pkt); + +/* action functions */ +extern void bta_fts_api_disable(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_api_authrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_api_accessrsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_api_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_ci_write(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_ci_read(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_ci_open(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_ci_resume(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_ci_direntry(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_connect(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_disc(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_close(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_abort(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_password(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_put(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_get(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_setpath(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_obx_action(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_appl_tout(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_conn_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_disc_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_gasp_err_rsp(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_close_complete(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_disable_cmpl(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); +extern void bta_fts_session_req(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); + +/* object store */ +extern UINT8 bta_fts_mkdir(BT_HDR *p_pkt, tBTA_FT_OPER *p_op); +extern UINT8 bta_fts_chdir(BT_HDR *p_pkt, BOOLEAN backup_flag, tBTA_FT_OPER *p_op); +extern void bta_fts_getdirlist(char *p_name); +extern void bta_fts_proc_get_file(char *p_name); +extern void bta_fts_proc_put_file(BT_HDR *p_pkt, char *p_name, BOOLEAN final_pkt, UINT8 oper); +extern void bta_fts_delete(tBTA_FTS_OBX_EVENT *p_evt, const char *p); +extern void bta_fts_req_app_access (tBTA_FT_OPER oper, tBTA_FTS_CB *p_cb); + +/* miscellaneous functions */ +extern void bta_fts_get_file_rsp(UINT8 rsp_code, UINT16 num_read); +extern void bta_fts_put_file_rsp(UINT8 rsp_code); +extern void bta_fts_end_of_list(UINT8 rsp_code); +extern UINT8 bta_fts_add_list_entry(void); +extern void bta_fts_clean_list(tBTA_FTS_CB *p_cb); +extern void bta_fts_clean_getput(tBTA_FTS_CB *p_cb, BOOLEAN is_aborted); +extern void bta_fts_disable_cleanup(tBTA_FTS_CB *p_cb); +extern void bta_fts_discard_data(UINT16 event, tBTA_FTS_DATA *p_data); + +#endif /* BTA_FTS_INT_H */ diff --git a/bta/ft/bta_fts_main.c b/bta/ft/bta_fts_main.c new file mode 100644 index 0000000..67be954 --- /dev/null +++ b/bta/ft/bta_fts_main.c @@ -0,0 +1,603 @@ +/***************************************************************************** +** +** Name: bta_fts_main.c +** +** Description: This file contains the file transfer server main functions +** and state machine. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#include <string.h> + +#include "bt_target.h" +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include "bta_fs_api.h" +#include "bta_fts_int.h" +#include "gki.h" +#include "utl.h" +#include "obx_api.h" +#include "rfcdefs.h" /* BT_PSM_RFCOMM */ + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + + +/* state machine action enumeration list */ +enum +{ + BTA_FTS_API_DISABLE, + BTA_FTS_API_AUTHRSP, + BTA_FTS_API_ACCESSRSP, + BTA_FTS_API_CLOSE, + BTA_FTS_CI_WRITE, + BTA_FTS_CI_READ, + BTA_FTS_CI_OPEN, + BTA_FTS_CI_DIRENTRY, + BTA_FTS_OBX_CONNECT, + BTA_FTS_OBX_DISC, + BTA_FTS_OBX_CLOSE, + BTA_FTS_OBX_ABORT, + BTA_FTS_OBX_PASSWORD, + BTA_FTS_OBX_PUT, + BTA_FTS_OBX_GET, + BTA_FTS_OBX_SETPATH, + BTA_FTS_CI_RESUME, + BTA_FTS_OBX_ACTION, + BTA_FTS_SESSION_REQ, + BTA_FTS_APPL_TOUT, + BTA_FTS_CONN_ERR_RSP, + BTA_FTS_DISC_ERR_RSP, + BTA_FTS_GASP_ERR_RSP, + BTA_FTS_CLOSE_COMPLETE, + BTA_FTS_DISABLE_CMPL, + BTA_FTS_IGNORE +}; + +/* type for action functions */ +typedef void (*tBTA_FTS_ACTION)(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data); + +/* action function list */ +const tBTA_FTS_ACTION bta_fts_action[] = +{ + bta_fts_api_disable, + bta_fts_api_authrsp, + bta_fts_api_accessrsp, + bta_fts_api_close, + bta_fts_ci_write, + bta_fts_ci_read, + bta_fts_ci_open, + bta_fts_ci_direntry, + bta_fts_obx_connect, + bta_fts_obx_disc, + bta_fts_obx_close, + bta_fts_obx_abort, + bta_fts_obx_password, + bta_fts_obx_put, + bta_fts_obx_get, + bta_fts_obx_setpath, + bta_fts_ci_resume, + bta_fts_obx_action, + bta_fts_session_req, + bta_fts_appl_tout, + bta_fts_conn_err_rsp, + bta_fts_disc_err_rsp, + bta_fts_gasp_err_rsp, + bta_fts_close_complete, + bta_fts_disable_cmpl +}; + + +/* state table information */ +#define BTA_FTS_ACTIONS 1 /* number of actions */ +#define BTA_FTS_NEXT_STATE 1 /* position of next state */ +#define BTA_FTS_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_fts_st_idle[][BTA_FTS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_FTS_API_ENABLE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_CI_RESUME, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST}, +/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_IDLE_ST} +}; + +/* state table for obex/rfcomm connection state */ +static const UINT8 bta_fts_st_listen[][BTA_FTS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_API_CLOSE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_OBX_CONNECT, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_OBX_PASSWORD, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST} +}; + +/* state table for wait for authentication response state */ +static const UINT8 bta_fts_st_w4_auth[][BTA_FTS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_API_AUTHRSP, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_API_CLOSE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_CONN_ERR_RSP, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_OBX_DISC, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_OBX_CLOSE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_APPL_TOUT, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST} +}; + +/* state table for open state */ +static const UINT8 bta_fts_st_connected[][BTA_FTS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_CONN_ST}, +/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST}, +/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_API_ACCESSRSP, BTA_FTS_CONN_ST}, +/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_API_CLOSE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_CI_WRITE, BTA_FTS_CONN_ST}, +/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_CI_READ, BTA_FTS_CONN_ST}, +/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_CI_OPEN, BTA_FTS_CONN_ST}, +/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_CI_DIRENTRY, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_SESSION_REQ, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_OBX_DISC, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_OBX_ABORT, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_W4_AUTH_ST}, +/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_OBX_CLOSE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_OBX_PUT, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_OBX_GET, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_OBX_SETPATH, BTA_FTS_CONN_ST}, +/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST}, +/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_OBX_ACTION, BTA_FTS_CONN_ST}, +/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_APPL_TOUT, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST}, +/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_GASP_ERR_RSP, BTA_FTS_CONN_ST}, +/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CONN_ST}, +/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST} +}; + +/* state table for closing state */ +static const UINT8 bta_fts_st_closing[][BTA_FTS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_FTS_API_DISABLE_EVT */ {BTA_FTS_API_DISABLE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_API_AUTHRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_API_ACCESSRSP_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_API_CLOSE_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_CI_WRITE_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_READ_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_OPEN_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_CI_DIRENTRY_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_OBX_CONN_EVT */ {BTA_FTS_SESSION_REQ, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_DISC_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_ABORT_EVT */ {BTA_FTS_OBX_ABORT, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_PASSWORD_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_CLOSE_EVT */ {BTA_FTS_OBX_CLOSE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_PUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_GET_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_SETPATH_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_CI_SESSION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_OBX_ACTION_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_APPL_TOUT_EVT */ {BTA_FTS_IGNORE, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_DISC_ERR_EVT */ {BTA_FTS_DISC_ERR_RSP, BTA_FTS_CONN_ST}, +/* BTA_FTS_GASP_ERR_EVT */ {BTA_FTS_GASP_ERR_RSP, BTA_FTS_CLOSING_ST}, +/* BTA_FTS_CLOSE_CMPL_EVT */ {BTA_FTS_CLOSE_COMPLETE, BTA_FTS_LISTEN_ST}, +/* BTA_FTS_DISABLE_CMPL_EVT */ {BTA_FTS_DISABLE_CMPL, BTA_FTS_IDLE_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_FTS_ST_TBL)[BTA_FTS_NUM_COLS]; + +/* state table */ +const tBTA_FTS_ST_TBL bta_fts_st_tbl[] = +{ + bta_fts_st_idle, + bta_fts_st_listen, + bta_fts_st_w4_auth, + bta_fts_st_connected, + bta_fts_st_closing +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* FTS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_FTS_CB bta_fts_cb; +#endif + +#if BTA_FTS_DEBUG == TRUE +static char *fts_evt_code(tBTA_FTS_INT_EVT evt_code); +static char *fts_state_code(tBTA_FTS_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_fts_sm_execute +** +** Description State machine event handling function for FTS +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_sm_execute(tBTA_FTS_CB *p_cb, UINT16 event, tBTA_FTS_DATA *p_data) +{ + tBTA_FTS_ST_TBL state_table; + UINT8 action; + int i; +#if BTA_FTS_DEBUG == TRUE + tBTA_FTS_STATE in_state = bta_fts_cb.state; + UINT16 in_event = event; + APPL_TRACE_EVENT3("FTS Event : State 0x%02x [%s], Event [%s]", in_state, + fts_state_code(in_state), + fts_evt_code(event)); +#endif + + /* look up the state table for the current state */ + state_table = bta_fts_st_tbl[p_cb->state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->state = state_table[event][BTA_FTS_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_FTS_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_FTS_IGNORE) + { + (*bta_fts_action[action])(p_cb, p_data); + } + else + { + /* discard fts data */ + bta_fts_discard_data(p_data->hdr.event, p_data); + break; + } + } + +#if BTA_FTS_DEBUG == TRUE + if (in_state != bta_fts_cb.state) + { + APPL_TRACE_DEBUG3("FTS State Change: [%s] -> [%s] after Event [%s]", + fts_state_code(in_state), + fts_state_code(bta_fts_cb.state), + fts_evt_code(in_event)); + } +#endif +} + +/******************************************************************************* +** +** Function bta_fts_api_enable +** +** Description Handle an api enable event. This function enables the FT +** Server by opening an Obex/Rfcomm channel and placing it into +** listen mode. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_fts_api_enable(tBTA_FTS_CB *p_cb, tBTA_FTS_DATA *p_data) +{ + tOBX_StartParams start_msg; + tBTA_FTS_API_ENABLE *p_api = &p_data->api_enable; + tOBX_TARGET target; + UINT16 len; + tOBX_STATUS status; + UINT16 mtu = OBX_MAX_MTU; + + /* initialize control block */ + memset(p_cb, 0, sizeof(tBTA_FTS_CB)); + + /* Allocate an aligned memory buffer to hold the root path and working directory */ + /* Add 1 byte for '\0' */ + len = p_bta_fs_cfg->max_path_len + 1; + if ((p_cb->p_rootpath = (char *)GKI_getbuf((UINT16)(len * 2))) != NULL) + { + p_cb->p_workdir = p_cb->p_rootpath + len; + memcpy(target.target, BTA_FTS_FOLDER_BROWSING_TARGET_UUID, BTA_FTS_UUID_LENGTH); + target.len = BTA_FTS_UUID_LENGTH; + + /* store parameters */ + p_cb->app_id = p_api->app_id; + p_cb->p_cback = p_api->p_cback; + p_cb->scn = BTM_AllocateSCN(); + + if (p_bta_ft_cfg->over_l2cap) + { + p_cb->psm = L2CA_AllocatePSM(); + BTM_SetSecurityLevel (FALSE, p_api->servicename, BTM_SEC_SERVICE_OBEX_FTP, + p_api->sec_mask, p_cb->psm, + 0, 0); + } + + p_cb->auth_enabled = p_api->auth_enabled; + + p_cb->fd = BTA_FS_INVALID_FD; + /* Initialize the current working directory to be the root directory */ + BCM_STRNCPY_S(p_cb->p_rootpath, len, p_api->p_root_path, len-1); + BCM_STRNCPY_S(p_cb->p_workdir, len, p_api->p_root_path, len-1); + + /* Register FTP security requirements with BTM */ + BTM_SetSecurityLevel(FALSE, p_api->servicename, BTM_SEC_SERVICE_OBEX_FTP, + p_api->sec_mask, BT_PSM_RFCOMM, + BTM_SEC_PROTO_RFCOMM, (UINT32)p_cb->scn); + + /* Start up the FTP service */ + memset (&start_msg, 0, sizeof(tOBX_StartParams)); + start_msg.p_target = ⌖ + + /* Make the MTU fit into one RFC frame */ + start_msg.mtu = mtu; + start_msg.scn = p_cb->scn; + start_msg.psm = p_cb->psm; + start_msg.srm = p_bta_ft_cfg->srm; + start_msg.nonce = p_bta_ft_cfg->nonce; + start_msg.max_suspend = p_bta_ft_cfg->max_suspend; + start_msg.authenticate = p_cb->auth_enabled; + + start_msg.auth_option = (p_bta_ft_cfg->userid_req) ? OBX_AO_USR_ID : OBX_AO_NONE; + start_msg.p_cback = bta_fts_obx_cback; + + start_msg.realm_len = p_api->realm_len; + start_msg.p_realm = p_api->realm; + start_msg.realm_charset = (tOBX_CHARSET) p_bta_ft_cfg->realm_charset; + + if ((status = OBX_StartServer (&start_msg, &p_cb->obx_handle)) == OBX_SUCCESS) + { + /* Set up the SDP record for file transfer service */ + bta_fts_sdp_register(p_cb, p_api->servicename); + + if (start_msg.nonce) + { + bta_fs_co_resume (BTA_FTS_CI_SESSION_EVT, p_cb->app_id); + } + else + { + p_data->resume_evt.status = BTA_FS_CO_FAIL; + bta_fts_ci_resume(p_cb, p_data); + } + } + else + APPL_TRACE_ERROR1("OBX_StartServer returns error (%d)", status); + } + else /* Cannot allocate resources to run Server */ + APPL_TRACE_ERROR0("Not enough Resources to run FTP Server"); + + p_cb->p_cback(BTA_FTS_ENABLE_EVT, 0); +} + +/******************************************************************************* +** +** Function bta_fts_hdl_event +** +** Description File transfer server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_fts_hdl_event(BT_HDR *p_msg) +{ +#if BTA_FTS_DEBUG == TRUE + tBTA_FTS_STATE in_state = bta_fts_cb.state; +#endif + + switch (p_msg->event) + { + case BTA_FTS_API_ENABLE_EVT: +#if BTA_FTS_DEBUG == TRUE + APPL_TRACE_EVENT3("FTS Event Handler: State 0x%02x [%s], Event [%s]", in_state, + fts_state_code(in_state), + fts_evt_code(p_msg->event)); +#endif + bta_fts_api_enable(&bta_fts_cb, (tBTA_FTS_DATA *) p_msg); + +#if BTA_FTS_DEBUG == TRUE + if (in_state != bta_fts_cb.state) + { + APPL_TRACE_DEBUG3("FTS State Change: [%s] -> [%s] after Event [%s]", + fts_state_code(in_state), + fts_state_code(bta_fts_cb.state), + fts_evt_code(p_msg->event)); + } +#endif + break; + + default: + + bta_fts_sm_execute(&bta_fts_cb, p_msg->event, (tBTA_FTS_DATA *) p_msg); + + if ( bta_fts_cb.state == BTA_FTS_CONN_ST ) + { + if (( bta_fts_cb.pm_state == BTA_FTS_PM_IDLE ) + &&( bta_fts_cb.obx_oper != FTS_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA FTS informs DM/PM busy state"); + bta_sys_busy( BTA_ID_FTS ,bta_fts_cb.app_id, bta_fts_cb.bd_addr); + bta_fts_cb.pm_state = BTA_FTS_PM_BUSY; + } + else if (( bta_fts_cb.pm_state == BTA_FTS_PM_BUSY ) + &&( bta_fts_cb.obx_oper == FTS_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA FTS informs DM/PM idle state"); + bta_sys_idle( BTA_ID_FTS ,bta_fts_cb.app_id, bta_fts_cb.bd_addr); + bta_fts_cb.pm_state = BTA_FTS_PM_IDLE; + } + } + else if ( bta_fts_cb.state == BTA_FTS_LISTEN_ST ) + { + /* initialize power management state */ + bta_fts_cb.pm_state = BTA_FTS_PM_BUSY; + } + + break; + } + + return (TRUE); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_FTS_DEBUG == TRUE + +/******************************************************************************* +** +** Function fts_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *fts_evt_code(tBTA_FTS_INT_EVT evt_code) +{ + switch(evt_code) + { + case BTA_FTS_API_DISABLE_EVT: + return "BTA_FTS_API_DISABLE_EVT"; + case BTA_FTS_API_AUTHRSP_EVT: + return "BTA_FTS_API_AUTHRSP_EVT"; + case BTA_FTS_API_ACCESSRSP_EVT: + return "BTA_FTS_API_ACCESSRSP_EVT"; + case BTA_FTS_API_CLOSE_EVT: + return "BTA_FTS_API_CLOSE_EVT"; + case BTA_FTS_CI_WRITE_EVT: + return "BTA_FTS_CI_WRITE_EVT"; + case BTA_FTS_CI_READ_EVT: + return "BTA_FTS_CI_READ_EVT"; + case BTA_FTS_CI_OPEN_EVT: + return "BTA_FTS_CI_OPEN_EVT"; + case BTA_FTS_CI_DIRENTRY_EVT: + return "BTA_FTS_CI_DIRENTRY_EVT"; + case BTA_FTS_OBX_CONN_EVT: + return "BTA_FTS_OBX_CONN_EVT"; + case BTA_FTS_OBX_DISC_EVT: + return "BTA_FTS_OBX_DISC_EVT"; + case BTA_FTS_OBX_ABORT_EVT: + return "BTA_FTS_OBX_ABORT_EVT"; + case BTA_FTS_OBX_PASSWORD_EVT: + return "BTA_FTS_OBX_PASSWORD_EVT"; + case BTA_FTS_OBX_CLOSE_EVT: + return "BTA_FTS_OBX_CLOSE_EVT"; + case BTA_FTS_OBX_PUT_EVT: + return "BTA_FTS_OBX_PUT_EVT"; + case BTA_FTS_OBX_GET_EVT: + return "BTA_FTS_OBX_GET_EVT"; + case BTA_FTS_OBX_SETPATH_EVT: + return "BTA_FTS_OBX_SETPATH_EVT"; + case BTA_FTS_OBX_ACTION_EVT: + return "BTA_FTS_OBX_ACTION_EVT"; + case BTA_FTS_CI_SESSION_EVT: + return "BTA_FTS_CI_SESSION_EVT"; + case BTA_FTS_APPL_TOUT_EVT: + return "BTA_FTS_APPL_TOUT_EVT"; + case BTA_FTS_DISC_ERR_EVT: + return "BTA_FTS_DISC_ERR_EVT"; + case BTA_FTS_GASP_ERR_EVT: + return "BTA_FTS_GASP_ERR_EVT"; + case BTA_FTS_API_ENABLE_EVT: + return "BTA_FTS_API_ENABLE_EVT"; + case BTA_FTS_CLOSE_CMPL_EVT: + return "BTA_FTS_CLOSE_CMPL_EVT"; + case BTA_FTS_DISABLE_CMPL_EVT: + return "BTA_FTS_DISABLE_CMPL_EVT"; + default: + return "unknown FTS event code"; + } +} + +/******************************************************************************* +** +** Function fts_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *fts_state_code(tBTA_FTS_STATE state_code) +{ + switch(state_code) + { + case BTA_FTS_IDLE_ST: + return "BTA_FTS_IDLE_ST"; + case BTA_FTS_LISTEN_ST: + return "BTA_FTS_LISTEN_ST"; + case BTA_FTS_W4_AUTH_ST: + return "BTA_FTS_W4_AUTH_ST"; + case BTA_FTS_CONN_ST: + return "BTA_FTS_CONN_ST"; + case BTA_FTS_CLOSING_ST: + return "BTA_FTS_CLOSING_ST"; + default: + return "unknown FTS state code"; + } +} + +#endif /* Debug Functions */ +#endif /* BTA_FT_INCLUDED */ diff --git a/bta/ft/bta_fts_sdp.c b/bta/ft/bta_fts_sdp.c new file mode 100644 index 0000000..2613942 --- /dev/null +++ b/bta/ft/bta_fts_sdp.c @@ -0,0 +1,66 @@ +/***************************************************************************** +** +** Name: bta_fts_sdp.c +** +** File: Implements the SDP functions used by File Transfer Server +** +** Copyright (c) 2003, Widcomm Inc., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include <string.h> + +#include "sdp_api.h" +#include "bta_fts_int.h" +#include "goep_util.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + +/***************************************************************************** +** +** Function: bta_fts_sdp_register() +** +** Purpose: Registers the File Transfer service with SDP +** +** Parameters: +** +** +** Returns: void +** +*****************************************************************************/ +void bta_fts_sdp_register (tBTA_FTS_CB *p_cb, char *p_service_name) +{ + UINT16 ftp_service = UUID_SERVCLASS_OBEX_FILE_TRANSFER; + tGOEP_ERRORS status = GOEP_ERROR; + UINT16 version = BTA_FTS_DEFAULT_VERSION; + UINT8 temp[4], *p; + + if (p_bta_ft_cfg->over_l2cap) + { + version = BTA_FT_ENHANCED_VERSION; + } + status = GOEP_Register (p_service_name, &p_cb->sdp_handle, p_cb->scn, 1, &ftp_service, + ftp_service, version); + + if (status == GOEP_SUCCESS) + { + if (p_bta_ft_cfg->over_l2cap) + { + /* add the psm */ + p = temp; + UINT16_TO_BE_STREAM(p, p_cb->psm); + SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_OBX_OVR_L2CAP_PSM, UINT_DESC_TYPE, + (UINT32)2, (UINT8*)temp); + } + + + bta_sys_add_uuid(ftp_service); /* UUID_SERVCLASS_OBEX_FILE_TRANSFER */ + APPL_TRACE_DEBUG1("FTS: SDP Registered (handle 0x%08x)", p_cb->sdp_handle); + } + + return; +} diff --git a/bta/ft/bta_fts_utils.c b/bta/ft/bta_fts_utils.c new file mode 100644 index 0000000..f689752 --- /dev/null +++ b/bta/ft/bta_fts_utils.c @@ -0,0 +1,972 @@ +/***************************************************************************** +** +** Name: bta_fts_utils.c +** +** Description: This file implements object store functions for the +** file transfer server. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_FT_INCLUDED) && (BTA_FT_INCLUDED == TRUE) + +#include <stdio.h> +#include <string.h> +#include "bta_fs_api.h" +#include "bta_fts_int.h" +#include "bta_fs_co.h" +#include "gki.h" +#include "utl.h" + +/******************************************************************************* +** Constants +*******************************************************************************/ + +/******************************************************************************* +** Local Function Prototypes +*******************************************************************************/ + +/******************************************************************************* +* Macros for FTS +*******************************************************************************/ +#define BTA_FTS_XML_EOL "\n" +#define BTA_FTS_FOLDER_LISTING_START ( "<?xml version=\"1.0\"?>\n" \ + "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">\n" \ + "<folder-listing version=\"1.0\">\n" ) + +#define BTA_FTS_FOLDER_LISTING_END ( "</folder-listing>" ) +#define BTA_FTS_PARENT_FOLDER (" <parent-folder/>\n") + +#define BTA_FTS_FILE_ELEM "file" +#define BTA_FTS_FOLDER_ELEM "folder" +#define BTA_FTS_NAME_ATTR "name" +#define BTA_FTS_SIZE_ATTR "size" +#define BTA_FTS_TYPE_ATTR "type" +#define BTA_FTS_MODIFIED_ATTR "modified" +#define BTA_FTS_CREATED_ATTR "created" +#define BTA_FTS_ACCESSED_ATTR "accessed" +#define BTA_FTS_USER_PERM_ATTR "user-perm" + +/******************************************************************************* +* Exported Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function bta_fts_getdirlist +** +** Description Processes the retrieval of a directory listing. +** +** Parameters p_pkt - Pointer to the OBX Get request +** name directory to list. +** +** +** Returns UINT8 - OBX response code. OBX_RSP_OK if initiated. +** +*******************************************************************************/ +void bta_fts_getdirlist(char *p_name) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTS_DIRLIST *p_dir = &p_cb->dir; + UINT16 temp_len; + BOOLEAN is_dir; + UINT8 rsp_code = OBX_RSP_OK; + + if (!p_cb->p_path) + p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1)); + if (p_cb->p_path) + { + /* If not specified, use the current work directory */ + if (!p_name || p_name[0] == '\0') + { + p_cb->p_path[p_bta_fs_cfg->max_path_len] = 0; + BCM_STRNCPY_S(p_cb->p_path, (p_bta_fs_cfg->max_path_len + 1), p_cb->p_workdir, p_bta_fs_cfg->max_path_len); + } + else + { + if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2) <= p_bta_fs_cfg->max_path_len) + { + sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir, + p_bta_fs_cfg->path_separator, p_name); + + /* Make sure the Name is a directory and accessible */ + if (((bta_fs_co_access(p_cb->p_path, BTA_FS_ACC_EXIST, + &is_dir, p_cb->app_id))!= BTA_FS_CO_OK) + || !is_dir) + rsp_code = OBX_RSP_NOT_FOUND; + } + else + rsp_code = OBX_RSP_BAD_REQUEST; + } + + /* Build the listing */ + if (rsp_code == OBX_RSP_OK) + { + if (!(strcmp(p_cb->p_path, p_cb->p_rootpath))) + p_dir->is_root = TRUE; + else + p_dir->is_root = FALSE; + + p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu); + + if (!p_dir->p_entry) + { + /* Allocate enough space for the structure and the file name */ + if ((p_dir->p_entry = (tBTA_FS_DIRENTRY *) + GKI_getbuf((UINT16)(sizeof(tBTA_FS_DIRENTRY) + + p_bta_fs_cfg->max_file_len + 1))) != NULL) + p_dir->p_entry->p_name = (char *)(p_dir->p_entry + 1); + } + + if (p_dir->p_entry && p_obx->p_pkt) + { + /* Add the start of the Body Header */ + p_obx->offset = 0; + p_obx->bytes_left = 0; + p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left); + + /* Is this a new request or continuation? */ + if ((p_cb->obx_oper == FTS_OP_NONE)) + { + p_cb->obx_oper = FTS_OP_LISTING; + APPL_TRACE_EVENT1("FTS List Directory: Name [%s]", p_cb->p_path); + + temp_len = strlen(BTA_FTS_FOLDER_LISTING_START); + + /* Add the beginning label of http */ + memcpy(p_obx->p_start, BTA_FTS_FOLDER_LISTING_START, temp_len); + p_obx->bytes_left -= (UINT16)(temp_len + strlen(BTA_FTS_FOLDER_LISTING_END)); + p_obx->offset += temp_len; + + /* Add the parent directory if not the root */ + if (strcmp(p_cb->p_path, p_cb->p_rootpath)) + { + temp_len = strlen(BTA_FTS_PARENT_FOLDER); + memcpy(p_obx->p_start + p_obx->offset, + BTA_FTS_PARENT_FOLDER, temp_len); + p_obx->bytes_left -= temp_len; + p_obx->offset += temp_len; + } + + p_cb->cout_active = TRUE; + bta_fs_co_getdirentry (p_cb->p_path, TRUE, p_dir->p_entry, + BTA_FTS_CI_DIRENTRY_EVT, p_cb->app_id); + + /* List is not complete, so don't send the response yet */ + rsp_code = OBX_RSP_PART_CONTENT; + } + else /* Add the entry previously retrieved */ + rsp_code = bta_fts_add_list_entry(); + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + } + else /* Error occurred */ + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + /* Response goes out if complete or error occurred */ + if (rsp_code != OBX_RSP_PART_CONTENT) + bta_fts_end_of_list(rsp_code); +} + +/******************************************************************************* +** +** Function bta_fts_proc_get_file +** +** Description Processes a Get File Operation. +** If first OBX request, the file is opened, otherwise if it is +** a continuation the next read is initiated. +** +** Parameters p_pkt - Pointer to the OBX Get request +** name of file to read. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_proc_get_file(char *p_name) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + p_obx->offset = 0; + + /* Allocate an OBX packet */ + if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, + p_cb->peer_mtu)) != NULL) + { + /* Is this a new request or continuation? */ + if ((p_cb->obx_oper == FTS_OP_NONE)) + { + /* Validate the name */ + if (p_name) + { + if ((p_cb->p_path = + (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + /* Build a fully qualified path */ + if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2) + <= p_bta_fs_cfg->max_path_len) + { + rsp_code = OBX_RSP_OK; + sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir, + p_bta_fs_cfg->path_separator, p_name); + + APPL_TRACE_EVENT1("FTS GET FILE: Name [%s]", p_cb->p_path); + + p_cb->obx_oper = FTS_OP_GET_FILE; + + /* Notify the application that a get file has been requested */ + bta_fts_req_app_access (BTA_FT_OPER_GET, p_cb); + } + } + } + } + else /* Continue reading from the file */ + { + /* Add the start of the Body Header */ + p_obx->bytes_left = 0; + p_obx->p_start = OBX_AddBodyStart(p_obx->p_pkt, &p_obx->bytes_left); + + rsp_code = OBX_RSP_OK; + p_cb->cout_active = TRUE; + bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset], + p_obx->bytes_left, BTA_FTS_CI_READ_EVT, 0, p_cb->app_id); + } + } + if (rsp_code != OBX_RSP_OK) + bta_fts_get_file_rsp(rsp_code, 0); +} + +/******************************************************************************* +** +** Function bta_fts_proc_put_file +** +** Description Processes a Put File Operation. +** Initiates the opening of a file for writing, or continues +** with a new Obx packet of data (continuation). +** +** Parameters p_pkt - Pointer to the OBX Put request +** name of file to write out. +** +** +** Returns void +** +*******************************************************************************/ +void bta_fts_proc_put_file(BT_HDR *p_pkt, char *p_name, BOOLEAN final_pkt, UINT8 oper) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FS_CO_STATUS status; + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + UINT8 num_hdrs; + BOOLEAN is_dir; + BOOLEAN endpkt; + + p_obx->final_pkt = final_pkt; + p_obx->p_pkt = p_pkt; + p_obx->offset = 0; /* Initial offset into OBX data */ + APPL_TRACE_DEBUG2("bta_fts_proc_put_file len:%d p_pkt->offset:%d", p_pkt->len, p_pkt->offset); + + /* Is this a new request or continuation? */ + if ((p_cb->obx_oper == FTS_OP_NONE)) + { + /* See if the folder permissions are writable in the current folder */ + if (((status = bta_fs_co_access(p_cb->p_workdir, BTA_FS_ACC_RDWR, + &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir) + { + /* Initialize the start of data and length */ + if ((p_cb->p_path = + (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + /* Build a fully qualified path */ + if ((strlen(p_cb->p_workdir) + strlen(p_name) + 2) + <= p_bta_fs_cfg->max_path_len) + { + /* Read the file length if header exists */ + if (!OBX_ReadLengthHdr(p_pkt, &p_cb->file_length)) + p_cb->file_length = BTA_FS_LEN_UNKNOWN; + + rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */ + sprintf(p_cb->p_path, "%s%c%s", p_cb->p_workdir, + p_bta_fs_cfg->path_separator, p_name); + + APPL_TRACE_DEBUG2("FTS PUT FILE: Name [%s], Length = 0x%0x (0 = n/a)", + p_cb->p_path, p_cb->file_length); + + p_cb->obx_oper = FTS_OP_PUT_FILE; + + /* Get permission before proceeding */ + bta_fts_req_app_access(BTA_FT_OPER_PUT, p_cb); + } + } + } + else + rsp_code = OBX_RSP_UNAUTHORIZED; + } + else /* Continue writing to the open file */ + { + /* Read in start of body if there is a body header */ + num_hdrs = OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start, + &p_obx->bytes_left, &endpkt); + if (num_hdrs == 1) + { + if (p_obx->bytes_left) + { + rsp_code = OBX_RSP_PART_CONTENT; /* Do not send OBX response yet */ + p_cb->cout_active = TRUE; + bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset], + p_obx->bytes_left, BTA_FTS_CI_WRITE_EVT, 0, p_cb->app_id); + } + else + { + rsp_code = OBX_RSP_OK; + } + + } + else if (oper & FTS_OP_RESUME) + { + rsp_code = OBX_RSP_OK; + } + else + { + bta_fts_clean_getput(p_cb, TRUE); + rsp_code = OBX_RSP_BAD_REQUEST; + } + } + + if (rsp_code != OBX_RSP_PART_CONTENT) + bta_fts_put_file_rsp(rsp_code); +} + +/******************************************************************************* +** +** Function bta_fts_mkdir +** +** Description make a new directory and sets the new path to this directory +** if successful. +** +** Parameters p_pkt - Pointer to the OBX packet +** +** Returns UINT8 - OBX response code +** +*******************************************************************************/ +UINT8 bta_fts_mkdir(BT_HDR *p_pkt, tBTA_FT_OPER *p_op) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FS_CO_STATUS status = BTA_FS_CO_FAIL; + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + char *p_newpath; + char *p_name; + BOOLEAN is_dir; + + p_newpath = p_cb->p_path; + p_name = p_cb->p_name; + + /* the name of the directory being created */ + if (p_cb->p_name && p_cb->p_name[0]) + { + /* Make sure the new path is not too big */ + if ((strlen(p_name) + strlen(p_cb->p_workdir) + 1) <= p_bta_fs_cfg->max_path_len) + { + /* create a temporary path for creation attempt */ + sprintf(p_newpath, "%s%c%s", p_cb->p_workdir, + p_bta_fs_cfg->path_separator, p_name); + + /* If the directory already exists, we're done */ + if (((status = bta_fs_co_access(p_newpath, BTA_FS_ACC_EXIST, + &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir) + { + /* If directory exists, skip mkdir and just issue chdir- Note OBX_RSP_CONTINUE used internally by callee */ + rsp_code = OBX_RSP_CONTINUE; + } + + /* See if the folder permissions are writable in the current folder */ + else if (((status = bta_fs_co_access(p_cb->p_workdir, BTA_FS_ACC_RDWR, + &is_dir, p_cb->app_id)) == BTA_FS_CO_OK)) + { + *p_op = BTA_FT_OPER_MK_DIR; + } + else if (status == BTA_FS_CO_EACCES) + rsp_code = OBX_RSP_UNAUTHORIZED; /* Read only folder, cannot create a new one */ + } + else + APPL_TRACE_WARNING0 ("bta_fts_mkdir: path too long!!!"); + } + else + rsp_code = OBX_RSP_BAD_REQUEST; + + + APPL_TRACE_DEBUG2("bta_fts_mkdir: co_status [%d], obx_rsp_code [0x%02x]", + status, rsp_code); + + return (rsp_code); +} + +/******************************************************************************* +** +** Function bta_fts_chdir +** +** Description Changes the current path to the specified directory. +** +** Parameters p_pkt - Pointer to the OBX packet +** backup_flag - if TRUE, path adjusted up one level. +** +** Returns UINT8 - OBX response code +** +*******************************************************************************/ +UINT8 bta_fts_chdir(BT_HDR *p_pkt, BOOLEAN backup_flag, tBTA_FT_OPER *p_op) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + char *p_path = p_cb->p_path; + char *p_name = p_cb->p_name; + char *p_workdir = p_cb->p_workdir; + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + BOOLEAN is_dir; + + if (!backup_flag) + { + + /* If No Name header, or empty name header, set to root path */ + if (p_name == NULL || (p_name && p_name[0] == '\0')) + { + BCM_STRNCPY_S(p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len); + p_workdir[p_bta_fs_cfg->max_path_len] = '\0'; + + rsp_code = OBX_RSP_OK; + APPL_TRACE_DEBUG0("FTS: Setting current path to ROOT"); + } +// btla-specific ++ + #if defined (FTS_REJECT_INVALID_OBEX_SET_PATH_REQ) && (FTS_REJECT_INVALID_OBEX_SET_PATH_REQ == TRUE) + /* Reject invalid OBEX set path reqeust - DOS or unix/linux like change directory*/ + else if(strncmp("/", p_name, 1) == 0 || strncmp("..", p_name, 2) == 0) + { + APPL_TRACE_ERROR0("FTS: Rejecting invalid chdir request start with / or .."); + rsp_code = OBX_RSP_NOT_FOUND; + } + #endif +// btla-specific -- + /* Make sure the new path is not too big */ + else if ((strlen(p_name) + strlen(p_workdir) + 2) + <= p_bta_fs_cfg->max_path_len) + { + /* create a temporary path for creation attempt */ + sprintf(p_path, "%s%c%s", p_workdir, + p_bta_fs_cfg->path_separator, p_name); + + if (((bta_fs_co_access(p_path, BTA_FS_ACC_EXIST, + &is_dir, p_cb->app_id)) == BTA_FS_CO_OK) && is_dir) + { + *p_op = BTA_FT_OPER_CHG_DIR; + } + else + rsp_code = OBX_RSP_NOT_FOUND; + } + } + else /* Backing up a directory */ + { + /* Backup unless already at root */ + if (strcmp(p_workdir, p_cb->p_rootpath)) + { + /* if an empty name header exist(although illegal), goes to root */ + if (p_name && p_name[0] == '\0') + { + BCM_STRNCPY_S(p_workdir, p_bta_fs_cfg->max_path_len+1, p_cb->p_rootpath, p_bta_fs_cfg->max_path_len); + p_workdir[p_bta_fs_cfg->max_path_len] = '\0'; + + APPL_TRACE_DEBUG0("FTS: Setting current path to ROOT"); + } + /* otherwise back up one level */ + /* Find the last occurrence of separator and replace with '\0' */ + else if((p_path = strrchr(p_workdir, (int)p_bta_fs_cfg->path_separator)) != NULL) + *p_path = '\0'; + APPL_TRACE_DEBUG1("FTS: SET NEW PATH [%s]", p_cb->p_workdir); + + rsp_code = OBX_RSP_OK; + } + else + rsp_code = OBX_RSP_NOT_FOUND; + } + + if (rsp_code == OBX_RSP_OK) + bta_fs_co_setdir(p_workdir, p_cb->app_id); + + return (rsp_code); +} + +/******************************************************************************* +** +** Function bta_fts_delete +** +** Description remove a file or directory +** +** Parameters +** p - Pointer to the name of the object store. It is +** converted into a fully qualified path before call-out +** function is called (if not a RAM object). +** +** Returns void +** +** Obex packet is responded to with: +** OBX_RSP_OK if successful, +** OBX_RSP_PRECONDTN_FAILED if a directory and not empty, +** OBX_RSP_UNAUTHORIZED if read only (access problem), +** OBX_RSP_INTRNL_SRVR_ERR otherwise. +** +*******************************************************************************/ +void bta_fts_delete(tBTA_FTS_OBX_EVENT *p_evt, const char *p_name) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + char *p_path; + tBTA_FS_CO_STATUS status; + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + BOOLEAN is_dir; + tBTA_FT_OPER ft_op = BTA_FT_OPER_DEL_FILE; + BOOLEAN rsp_now = TRUE; + + if ((p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 2))) != NULL) + { + p_path = p_cb->p_path; + sprintf(p_path, "%s%c%s", p_cb->p_workdir, p_bta_fs_cfg->path_separator, + p_name); + + /* Access the object to see if it exists */ + status = bta_fs_co_access(p_path, BTA_FS_ACC_RDWR, &is_dir, p_cb->app_id); + if (status == BTA_FS_CO_OK) + { + if (is_dir) + ft_op = BTA_FT_OPER_DEL_DIR; + rsp_now = FALSE; + bta_fts_req_app_access(ft_op, p_cb); + } + else if (status == BTA_FS_CO_EACCES) + rsp_code = OBX_RSP_UNAUTHORIZED; + else + rsp_code = OBX_RSP_NOT_FOUND; + + } + if(rsp_now) + { + utl_freebuf((void**)&p_cb->p_path); + OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_fts_end_of_list +** +** Description Finishes up the end body of the listing, and sends out the +** OBX response +** +** Returns void +** +*******************************************************************************/ +void bta_fts_end_of_list(UINT8 rsp_code) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + UINT16 temp_len; + + /* Add the end of folder listing string if successful operation */ + if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE) + { + /* If listing has completed, add on end string (http) */ + if (rsp_code == OBX_RSP_OK) + { + temp_len = strlen(BTA_FTS_FOLDER_LISTING_END); + memcpy(&p_obx->p_start[p_obx->offset], BTA_FTS_FOLDER_LISTING_END, temp_len); + p_obx->offset += temp_len; + + OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, TRUE); + + /* Clean up control block */ + bta_fts_clean_list(p_cb); + } + else /* More listing data to be sent */ + OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, FALSE); + + OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt); + p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */ + } + else /* An error occurred */ + { + OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); + bta_fts_clean_list(p_cb); + } +} + +/******************************************************************************* +** +** Function bta_fts_get_file_rsp +** +** Description Finishes up the end body of the file get, and sends out the +** OBX response +** +** Returns void +** +*******************************************************************************/ +void bta_fts_get_file_rsp(UINT8 rsp_code, UINT16 num_read) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTS param; + BOOLEAN done = TRUE; + + /* Send the response packet if successful operation */ + if (rsp_code == OBX_RSP_OK || rsp_code == OBX_RSP_CONTINUE) + { + p_obx->offset += num_read; + + /* More to be sent */ + if (rsp_code == OBX_RSP_CONTINUE) + { + if (p_obx->bytes_left != num_read) + APPL_TRACE_WARNING2("FTS Read: Requested (0x%04x), Read In (0x%04x)", + p_obx->bytes_left, num_read); + done = FALSE; + } + + OBX_AddBodyEnd(p_obx->p_pkt, p_obx->p_start, p_obx->offset, done); + + /* Notify application with progress */ + if (num_read) + { + param.prog.bytes = num_read; + param.prog.file_size = p_cb->file_length; + p_cb->p_cback(BTA_FTS_PROGRESS_EVT, ¶m); + } + } + else + p_cb->obx_oper = FTS_OP_NONE; + + OBX_GetRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)p_obx->p_pkt); + p_obx->p_pkt = NULL; /* Do not deallocate buffer; OBX will */ + + /* Final response packet sent out */ + if (done) + bta_fts_clean_getput(p_cb, FALSE); +} + +/******************************************************************************* +** +** Function bta_fts_put_file_rsp +** +** Description Responds to a put request, and closes the file if finished +** +** Returns void +** +*******************************************************************************/ +void bta_fts_put_file_rsp(UINT8 rsp_code) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTS param; + + /* Finished with input packet */ + utl_freebuf((void**)&p_obx->p_pkt); + + if (rsp_code == OBX_RSP_OK) + { + /* Update application if file data was transferred */ + if (p_obx->bytes_left) + { + param.prog.bytes = p_obx->bytes_left; + param.prog.file_size = p_cb->file_length; + p_cb->p_cback(BTA_FTS_PROGRESS_EVT, ¶m); + } + + /* If not end of file put, set the continue response */ + if (!p_obx->final_pkt) + rsp_code = OBX_RSP_CONTINUE; + else /* Done - free the allocated memory */ + bta_fts_clean_getput(p_cb, FALSE); + } + else + p_cb->obx_oper = FTS_OP_NONE; + + OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); +} + +/******************************************************************************* +** +** Function bta_fts_add_list_entry +** +** Description used by bta_fts_getdirlist to write a list entry to an +** obex packet (byte array). +** +** Returns UINT8 - OBX response code +** OBX_RSP_PART_CONTENT if not finished yet. +** OBX_RSP_CONTINUE [packet done] +** Others send error response out +** +*******************************************************************************/ +UINT8 bta_fts_add_list_entry(void) +{ + tBTA_FTS_CB *p_cb = &bta_fts_cb; + tBTA_FTS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FTS_DIRLIST *p_dir = &p_cb->dir; + tBTA_FS_DIRENTRY *p_file = p_dir->p_entry; + char *p_buf; + UINT16 size; + UINT8 rsp_code = OBX_RSP_PART_CONTENT; + + if ((p_buf = (char *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL) + { + p_buf[0] = '\0'; + + APPL_TRACE_DEBUG2("bta_fts_add_list_entry: attr:0x%02x, name:%s", + p_file->mode, p_file->p_name); + + if(p_file->mode & BTA_FS_A_DIR) /* Subdirectory */ + { + /* ignore "." and ".." */ + if (strcmp(p_file->p_name, ".") && strcmp(p_file->p_name, "..")) + { + sprintf(p_buf, " <" BTA_FTS_FOLDER_ELEM " " + BTA_FTS_NAME_ATTR "=\"%s\"/>" BTA_FTS_XML_EOL, + p_file->p_name); + } + } + else /* treat anything else as file */ + { + /* Add the creation time if valid */ + if (p_file->crtime[0] != '\0') + { + sprintf(p_buf, " <" BTA_FTS_FILE_ELEM " " + BTA_FTS_NAME_ATTR "=\"%s\" " + BTA_FTS_SIZE_ATTR "=\"%lu\" " + BTA_FTS_USER_PERM_ATTR "=\"R%s\" " + BTA_FTS_CREATED_ATTR "=\"%s\"/>" BTA_FTS_XML_EOL, + p_file->p_name, + p_file->filesize, + p_file->mode & BTA_FS_A_RDONLY ? "" : "WD", + p_file->crtime); + } + else + { + sprintf(p_buf, " <" BTA_FTS_FILE_ELEM " " + BTA_FTS_NAME_ATTR "=\"%s\" " + BTA_FTS_SIZE_ATTR "=\"%lu\" " + BTA_FTS_USER_PERM_ATTR "=\"R%s\"/>" BTA_FTS_XML_EOL, + p_file->p_name, + p_file->filesize, + p_file->mode & BTA_FS_A_RDONLY ? "" : "WD"); + } + } + + /* Make sure the entry fits into the current obx packet */ + size = strlen(p_buf); + if (size <= p_obx->bytes_left) + { + if (size > 0) + { + memcpy (&p_obx->p_start[p_obx->offset], p_buf, size); + p_obx->offset += size; + p_obx->bytes_left -= size; + } + /* Get the next directory entry */ + p_cb->cout_active = TRUE; + bta_fs_co_getdirentry (p_cb->p_path, FALSE, p_dir->p_entry, + BTA_FTS_CI_DIRENTRY_EVT, p_cb->app_id); + } + else /* entry did not fit in current obx packet; try to add entry in next obx req */ + rsp_code = OBX_RSP_CONTINUE; + + /* Done with temporary buffer */ + GKI_freebuf(p_buf); + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + return (rsp_code); +} + + +/******************************************************************************* +* Static Functions +*******************************************************************************/ + +/******************************************************************************* +** +** Function bta_fts_clean_list +** +** Description Cleans up the get directory list memory and control block +** +** Returns void +** +******************************************* +************************************/ +void bta_fts_clean_list(tBTA_FTS_CB *p_cb) +{ + tBTA_FTS_DIRLIST *p_dir = &p_cb->dir; + /* Clean up control block */ + p_cb->obx_oper = FTS_OP_NONE; + utl_freebuf((void**)&p_cb->p_name); + utl_freebuf((void**)&p_dir->p_entry); + utl_freebuf((void**)&p_cb->p_path); +} + +/******************************************************************************* +** +** Function bta_fts_clean_getput +** +** Description Cleans up the get/put resources and control block +** +** Returns void +** +*******************************************************************************/ +void bta_fts_clean_getput(tBTA_FTS_CB *p_cb, BOOLEAN is_aborted) +{ + tBTA_FS_CO_STATUS status; + tBTA_FTS_OBJECT objdata; + tBTA_FTS_EVT evt = 0; + + /* Clean up control block */ + utl_freebuf((void**)&p_cb->obx.p_pkt); + + /* Close any open files */ + if (p_cb->fd >= 0) + { + bta_fs_co_close(p_cb->fd, p_cb->app_id); + p_cb->fd = BTA_FS_INVALID_FD; + + /* Notify the application */ + objdata.p_name = p_cb->p_path; + + if (is_aborted) + objdata.status = BTA_FTS_FAIL; + else + objdata.status = BTA_FTS_OK; + + if (p_cb->obx_oper == FTS_OP_PUT_FILE) + { + /* Delete an aborted unfinished push file operation */ + if (is_aborted && p_cb->suspending == FALSE) + { + status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id); + APPL_TRACE_WARNING2("FTS: Remove ABORTED Push File Operation [%s], status 0x%02x", + p_cb->p_path, status); + } + + evt = BTA_FTS_PUT_CMPL_EVT; + } + else if (p_cb->obx_oper == FTS_OP_GET_FILE) + { + evt = BTA_FTS_GET_CMPL_EVT; + } + + if (evt) + { + /* Notify application of operation complete */ + p_cb->p_cback(evt, (tBTA_FTS *)&objdata); + } + } + + p_cb->suspending = FALSE; + + utl_freebuf((void**)&p_cb->p_name); + utl_freebuf((void**)&p_cb->p_path); + + p_cb->obx_oper = FTS_OP_NONE; + p_cb->obx.bytes_left = 0; + p_cb->file_length = BTA_FS_LEN_UNKNOWN; + p_cb->acc_active = 0; +} + +/******************************************************************************* +** +** Function bta_fts_disable_cleanup +** +** Description Cleans up the resources and control block +** +** Returns void +** +*******************************************************************************/ +void bta_fts_disable_cleanup(tBTA_FTS_CB *p_cb) +{ + tBTA_FS_CO_STATUS status; + + /* Stop the OBEX server */ + OBX_StopServer(p_cb->obx_handle); + + /* Clean up control block */ + utl_freebuf((void **)&p_cb->obx.p_pkt); + + /* Close any open files */ + if (p_cb->fd >= 0) + { + bta_fs_co_close(p_cb->fd, p_cb->app_id); + p_cb->fd = BTA_FS_INVALID_FD; + + /* Delete an aborted unfinished push file operation */ + if (p_cb->obx_oper == FTS_OP_PUT_FILE) + { + status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id); + APPL_TRACE_WARNING2("FTS: bta_fts_disable_cleanup() ->Remove ABORTED Push File Operation [%s], status 0x%02x", + p_cb->p_path, status); + } + } + + /* Free any used memory buffers */ + utl_freebuf((void **)&p_cb->dir.p_entry); + utl_freebuf((void **)&p_cb->p_name); + utl_freebuf((void **)&p_cb->p_path); + + /* Remove the FTP service from the SDP database */ + SDP_DeleteRecord(p_cb->sdp_handle); + + /* Free the allocated server channel number */ + BTM_FreeSCN(p_cb->scn); + + GKI_freebuf(p_cb->p_rootpath); /* Free buffer containing root and working paths */ + + p_cb->obx_oper = FTS_OP_NONE; + p_cb->obx.bytes_left = 0; + p_cb->file_length = BTA_FS_LEN_UNKNOWN; + p_cb->acc_active = 0; + + if (p_cb->p_cback) + { + /* Notify the application */ + p_cb->p_cback(BTA_FTS_DISABLE_EVT, 0); + p_cb->p_cback = NULL; + } +} + +/******************************************************************************* +** +** Function bta_fts_discard_data +** +** Description frees the data +** +** Returns void +** +*******************************************************************************/ +void bta_fts_discard_data(UINT16 event, tBTA_FTS_DATA *p_data) +{ + switch(event) + { + case BTA_FTS_OBX_CONN_EVT: + case BTA_FTS_OBX_DISC_EVT: + case BTA_FTS_OBX_ABORT_EVT: + case BTA_FTS_OBX_PASSWORD_EVT: + case BTA_FTS_OBX_CLOSE_EVT: + case BTA_FTS_OBX_PUT_EVT: + case BTA_FTS_OBX_GET_EVT: + case BTA_FTS_OBX_SETPATH_EVT: + utl_freebuf((void**)&p_data->obx_evt.p_pkt); + break; + + default: + /*Nothing to free*/ + break; + } +} + +#endif /* BTA_FT_INCLUDED */ |