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/op | |
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/op')
-rw-r--r-- | bta/op/bta_op_fmt.c | 804 | ||||
-rw-r--r-- | bta/op/bta_op_fmt.h | 92 | ||||
-rw-r--r-- | bta/op/bta_op_vcal.c | 158 | ||||
-rw-r--r-- | bta/op/bta_op_vcard.c | 310 | ||||
-rw-r--r-- | bta/op/bta_op_vnote.c | 99 | ||||
-rw-r--r-- | bta/op/bta_opc_act.c | 1017 | ||||
-rw-r--r-- | bta/op/bta_opc_api.c | 214 | ||||
-rw-r--r-- | bta/op/bta_opc_int.h | 257 | ||||
-rw-r--r-- | bta/op/bta_opc_main.c | 425 | ||||
-rw-r--r-- | bta/op/bta_opc_utils.c | 322 | ||||
-rw-r--r-- | bta/op/bta_ops_act.c | 793 | ||||
-rw-r--r-- | bta/op/bta_ops_api.c | 153 | ||||
-rw-r--r-- | bta/op/bta_ops_int.h | 198 | ||||
-rw-r--r-- | bta/op/bta_ops_main.c | 412 | ||||
-rw-r--r-- | bta/op/bta_ops_utils.c | 487 |
15 files changed, 5741 insertions, 0 deletions
diff --git a/bta/op/bta_op_fmt.c b/bta/op/bta_op_fmt.c new file mode 100644 index 0000000..000370a --- /dev/null +++ b/bta/op/bta_op_fmt.c @@ -0,0 +1,804 @@ +/***************************************************************************** +** +** Name: bta_op_fmt.c +** +** Description: This file contains common functions and data structures +** used by the OPP object formatting functions. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include <string.h> +#include <ctype.h> +#include "bta_op_api.h" +#include "bta_op_fmt.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_OP_ENCODING_LEN 9 +#define BTA_OP_CHARSET_LEN 8 +#define BTA_OP_PARAM_TYPE_HDR_LEN 5 +#define BTA_OP_NUM_NONINLINE_MEDIA 2 + +const char bta_op_encoding[] = "ENCODING="; + +const tBTA_OP_PARAM bta_op_encodings[] = +{/* the len is (BTA_OP_ENCODING_LEN + 1 + strlen(p_name)) */ + {NULL, 0}, + {"QUOTED-PRINTABLE", 26}, /* BTA_OP_ENC_QUOTED_PRINTABLE */ + {"8BIT", 14}, /* BTA_OP_ENC_8BIT */ + {"b", 11}, /* BTA_OP_ENC_BINARY */ +// btla-specific ++ + {"BASE64", 16} /* BTA_OP_ENC_BASE64 */ +// btla-specific -- +}; + +#define BTA_OP_NUM_ENCODINGS 3 +#define BTA_OP_QP_IDX 1 /* array index for quoted printable in bta_op_encodings */ + +const char bta_op_charset[] = "CHARSET="; + +const char bta_op_param_type_hdr[] = "TYPE="; + +const tBTA_OP_PARAM bta_op_charsets[] = +{/* the len is (BTA_OP_CHARSET_LEN + 1 + strlen(p_name)) */ + {NULL, 0}, + {"BIG5", 13}, /* BTA_OP_CHAR_BIG5 */ + {"EUC-JP", 15}, /* BTA_OP_CHAR_EUC_JP */ + {"EUC-KR", 15}, /* BTA_OP_CHAR_EUC_KR */ + {"GB2312", 15}, /* BTA_OP_CHAR_GB2312 */ + {"ISO-2022-JP", 20}, /* BTA_OP_CHAR_ISO_2022_JP */ + {"ISO-8859-1", 19}, /* BTA_OP_CHAR_ISO_8859_1 */ + {"ISO-8859-2", 19}, /* BTA_OP_CHAR_ISO_8859_2 */ + {"ISO-8859-3", 19}, /* BTA_OP_CHAR_ISO_8859_3 */ + {"ISO-8859-4", 19}, /* BTA_OP_CHAR_ISO_8859_4 */ + {"ISO-8859-5", 19}, /* BTA_OP_CHAR_ISO_8859_5 */ + {"ISO-8859-6", 19}, /* BTA_OP_CHAR_ISO_8859_6 */ + {"ISO-8859-7", 19}, /* BTA_OP_CHAR_ISO_8859_7 */ + {"ISO-8859-8", 19}, /* BTA_OP_CHAR_ISO_8859_8 */ + {"KOI8-R", 15}, /* BTA_OP_CHAR_KOI8_R */ + {"SHIFT_JIS", 18}, /* BTA_OP_CHAR_SHIFT_JIS */ + {"UTF-8", 14} /* BTA_OP_CHAR_UTF_8 */ +}; + +#define BTA_OP_NUM_CHARSETS 16 + +/* Structure of the 32-bit parameters mask: +** (same comment is in bta_op_api.h) +** + property-specific +** +reserved | + character set +** | | | + encoding +** | | | | +** 0000000000000000 00000000 00000 000 +*/ +#define BTA_OP_GET_PARAM(param, encod, charset, specific) \ + encod = (UINT8) (param) & 0x00000007; \ + charset = (UINT8) ((param) >> 3) & 0x0000001F; \ + specific = (UINT8) ((param) >> 8) & 0x000000FF; + +/* mask for properties default 0, filter all */ +static UINT32 bta_op_prop_filter_mask = 0; + +const tBTA_OP_PROP_MEDIA bta_op_media[] = +{ + {NULL, 2}, + {"PHOTO", 5}, + {"SOUND", 5} +}; + +/* Place holder constant for safe string functions since there's no way to know how +** memory is remaining for input parameter to build property. +** Note: The BCM_STRCPY_S functions should be changed to know how much memory +** is remaining. When completed this constant can be removed. Also, if safe +** string functions are not used then this parameter is ignored anyway! +*/ +#ifndef BTA_OP_REM_MEMORY +#define BTA_OP_REM_MEMORY 8228 +#endif + +/******************************************************************************* +** +** Function bta_op_strnicmp +** +** Description Case insensitive strncmp. +** +** +** Returns void +** +*******************************************************************************/ +INT16 bta_op_strnicmp(const char *pStr1, const char *pStr2, size_t Count) +{ + char c1, c2; + INT16 v; + + if (Count == 0) + return 0; + + do { + c1 = *pStr1++; + c2 = *pStr2++; + /* the casts are necessary when pStr1 is shorter & char is signed */ + v = (UINT16) tolower(c1) - (UINT16) tolower(c2); + } while ((v == 0) && (c1 != '\0') && (--Count > 0)); + + return v; +} + +/******************************************************************************* +** +** Function bta_op_set_prop_mask +** +** Description Set property mask +** +** +** Returns void +** +*******************************************************************************/ +void bta_op_set_prop_filter_mask(UINT32 mask) +{ + bta_op_prop_filter_mask = mask; + return; +} + +/******************************************************************************* +** +** Function bta_op_prop_len +** +** Description Calculate the length of a property string through lookup +** tables. +** +** +** Returns Length of string in bytes. +** +*******************************************************************************/ +UINT16 bta_op_prop_len(const tBTA_OP_PROP_TBL *p_tbl, tBTA_OP_PROP *p_prop) +{ + UINT8 i_e, i_c, i_s; + UINT8 len_s = 0; + int i; + + /* parse parameters mask */ + BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s); + + /* calculate length of property-specific parameters, if any */ + if (p_tbl[p_prop->name].p_param_tbl != NULL) + { + for (i = 1; (i_s != 0) && (i <= p_tbl[p_prop->name].p_param_tbl[0].len); i++) + { + if (i_s & 1) + { + len_s += p_tbl[p_prop->name].p_param_tbl[i].len; + } + i_s >>= 1; + } + } + + return (p_tbl[p_prop->name].len + len_s + bta_op_charsets[i_c].len + + bta_op_encodings[i_e].len + p_prop->len); +} + +/******************************************************************************* +** +** Function bta_op_param_conflict +** +** Description Check if the parameters of the property for the format +** conflict/not allowed. +** +** +** Returns TRUE if not allowed, else FALSE +** +*******************************************************************************/ +BOOLEAN bta_op_param_conflict(tBTA_OP_SUP_FMT fmt, tBTA_OP_PROP *p_prop) +{ + UINT8 i_e, i_c, i_s; + BOOLEAN conflict = FALSE; + + if (p_prop->parameters != 0) + { + BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s); + + if (fmt == BTA_OP_FMT_VCARD30) + { + /* VCard 3.0 does not support CHARSET. If it is present, we + should ignore the whole property in the vCard build process */ + if (bta_op_charsets[i_c].p_name != NULL) + conflict = TRUE; + + /* VCard 3.0 only supports 'b' encoding. If any other encoding + ex. quoted-printable, is present, then whole property is ignored */ + if ((bta_op_encodings[i_e].p_name != NULL) && strcmp(bta_op_encodings[i_e].p_name, "b")) + conflict = TRUE; + } + } + + return conflict; +} +/******************************************************************************* +** +** Function bta_op_add_param +** +** Description Add parameter strings to a property string. +** +** +** Returns Pointer to the next byte after the end of the string. +** +*******************************************************************************/ +UINT8 *bta_op_add_param(tBTA_OP_SUP_FMT fmt, const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p, tBTA_OP_PROP *p_prop) +{ + UINT8 i_e, i_c, i_s; + int i; + UINT8 bta_op_param_type_delimit = 0; + + if (p_prop->parameters != 0) + { + BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s); + + /* add encoding parameter */ + if (bta_op_encodings[i_e].p_name != NULL) + { + *p++ = ';'; + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encoding); + p += BTA_OP_ENCODING_LEN; + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encodings[i_e].p_name); + p += bta_op_encodings[i_e].len - BTA_OP_ENCODING_LEN - 1; + } + + /* add character set parameter */ + if (bta_op_charsets[i_c].p_name != NULL) + { + *p++ = ';'; + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_charset); + p += BTA_OP_CHARSET_LEN; + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_charsets[i_c].p_name); + p += bta_op_charsets[i_c].len - BTA_OP_CHARSET_LEN - 1; + } + + /* add any property-specific parameters */ + if (p_tbl[p_prop->name].p_param_tbl != NULL) + { + for (i = 1; (i_s != 0) && (i <= p_tbl[p_prop->name].p_param_tbl[0].len); i++) + { + if (i_s & 1) + { + if (bta_op_param_type_delimit) + { + *p++ = ','; + } + else + { + *p++ = ';'; + + if (fmt == BTA_OP_FMT_VCARD30) + { + BCM_STRNCPY_S((char *) p, BTA_OP_PARAM_TYPE_HDR_LEN+1, bta_op_param_type_hdr, BTA_OP_PARAM_TYPE_HDR_LEN); + p += BTA_OP_PARAM_TYPE_HDR_LEN; + bta_op_param_type_delimit++; + } + } + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_tbl[p_prop->name].p_param_tbl[i].p_name); + p += p_tbl[p_prop->name].p_param_tbl[i].len - 1; + } + i_s >>= 1; + } + } + } + else if (p_prop->p_param) + { + *p++ = ';'; + memcpy((char *) p, p_prop->p_param, p_prop->param_len); + p += p_prop->param_len; + } + + return p; +} + +/******************************************************************************* +** +** Function bta_op_add_media_param +** +** Description Add parameter strings to a media property string. +** +** +** Returns Pointer to the next byte after the end of the string. +** +*******************************************************************************/ +UINT8 *bta_op_add_media_param(const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p, tBTA_OP_PROP *p_prop) +{ + UINT8 i_e, i_c, i_s; + int i; + + if (p_prop->parameters != 0) + { + BTA_OP_GET_PARAM(p_prop->parameters, i_e, i_c, i_s); + + /* add encoding parameter */ + if (bta_op_encodings[i_e].p_name != NULL) + { + *p++ = ';'; + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encoding); + p += BTA_OP_ENCODING_LEN; + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, bta_op_encodings[i_e].p_name); + p += bta_op_encodings[i_e].len - BTA_OP_ENCODING_LEN - 1; + } + + /* add any property-specific parameters */ + if (p_tbl[p_prop->name].p_param_tbl != NULL) + { + for (i = 1; (i_s != 0) && (i <= p_tbl[p_prop->name].p_param_tbl[0].len); i++) + { + if (i_s & 1) + { + *p++ = ';'; + + /* Add "TYPE=" to non-referenced (inline) media */ + if (i > BTA_OP_NUM_NONINLINE_MEDIA) + { + BCM_STRNCPY_S((char *) p, BTA_OP_PARAM_TYPE_HDR_LEN+1, bta_op_param_type_hdr, BTA_OP_PARAM_TYPE_HDR_LEN); + p += BTA_OP_PARAM_TYPE_HDR_LEN; + } + + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_tbl[p_prop->name].p_param_tbl[i].p_name); + p += p_tbl[p_prop->name].p_param_tbl[i].len - 1; + break; + } + i_s >>= 1; + } + } + } + else if (p_prop->p_param) + { + *p++ = ';'; + memcpy((char *) p, p_prop->p_param, p_prop->param_len); + p += p_prop->param_len; + } + + return p; +} + +/******************************************************************************* +** +** Function bta_op_get_property_by_name +** +** Description Get the property user data by name. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if there is no property user data. +** +*******************************************************************************/ +tBTA_OP_STATUS bta_op_get_property_by_name(const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p_name, + tBTA_OP_PROP *p_prop, UINT8 num_prop, UINT8 *p_data, + UINT16 *p_len) +{ + int i, j; + tBTA_OP_STATUS result = BTA_OP_FAIL; + + /* for each property */ + for(i = 0; num_prop != 0; num_prop--, i++) + { + /* verify property is valid */ + if ((p_prop[i].name == 0) || (p_prop[i].name > p_tbl[0].len)) + { + result = BTA_OP_FAIL; + break; + } + + j = p_prop[i].name; + + if (bta_op_strnicmp(p_tbl[j].p_name, (char *) p_name, + (p_tbl[j].len - BTA_OP_PROP_OVHD)) == 0) + { + memcpy(p_data, p_prop[i].p_data, p_prop[i].len); + *p_len = p_prop[i].len; + result = BTA_OP_OK; + break; + } + } + return result; +} + +/******************************************************************************* +** +** Function bta_op_build_obj +** +** Description Build an object from property data supplied by the user. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete build. +** +*******************************************************************************/ +tBTA_OP_STATUS bta_op_build_obj(const tBTA_OP_OBJ_TBL *p_bld, UINT8 *p_data, + UINT16 *p_len, tBTA_OP_PROP *p_prop, UINT8 num_prop) +{ + int i,j; + tBTA_OP_STATUS result = BTA_OP_OK; + UINT8 *p = p_data; + + /* sanity check length */ + if (*p_len < p_bld->min_len) + { + result = BTA_OP_MEM; + } + else + { + /* adjust p_len to amount of free space minus start and end */ + *p_len -= p_bld->min_len; + + /* add begin, version */ + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_bld->p_begin_str); + p += p_bld->begin_len; + + /* for each property */ + for(i = 0; num_prop != 0; num_prop--, i++) + { + /* verify property is valid */ + if ((p_prop[i].name == 0) || (p_prop[i].name > p_bld->p_tbl[0].len)) + { + result = BTA_OP_FAIL; + break; + } + + /* verify property will fit */ + if (bta_op_prop_len(p_bld->p_tbl, &p_prop[i]) > (p_data + p_bld->begin_len + *p_len - p)) + { + result = BTA_OP_MEM; + break; + } + + /* check for filter */ + if (bta_op_prop_filter_mask !=0 && p_bld->p_prop_filter_mask_tbl != NULL && + p_prop[i].name <= p_bld->p_prop_filter_mask_tbl->len) + { + if (!(bta_op_prop_filter_mask & p_bld->p_prop_filter_mask_tbl->p_prop_filter_mask[p_prop[i].name])) + continue; + } + + /* Check if the combination of parameters are allowed for + the format we are building */ + if (bta_op_param_conflict(p_bld->fmt, &p_prop[i])) + continue; + + /* add property string */ + BCM_STRCPY_S((char *) p, BTA_OP_REM_MEMORY, p_bld->p_tbl[p_prop[i].name].p_name); + p += p_bld->p_tbl[p_prop[i].name].len - BTA_OP_PROP_OVHD; + + for (j= bta_op_media[0].len; j > 0; j--) + { + if (!bta_op_strnicmp(bta_op_media[j].media_name, p_bld->p_tbl[p_prop[i].name].p_name, bta_op_media[j].len)) + { + p = bta_op_add_media_param(p_bld->p_tbl, p, &p_prop[i]); + break; + } + } + + if (!j) + { + /* add property parameters */ + p = bta_op_add_param(p_bld->fmt, p_bld->p_tbl, p, &p_prop[i]); + } + + /* add user data */ +// btla-specific ++ + if(p_prop[i].name != BTA_OP_VCARD_CALL) // If the data is call date-time, use ';' instead of ':' + { + *p++ = ':'; + } + else + { + *p++ = ';'; + } +// btla-specific -- + + memcpy(p, p_prop[i].p_data, p_prop[i].len); + p += p_prop[i].len; + *p++ = '\r'; + *p++ = '\n'; + } + + /* add in end */ + memcpy(p, p_bld->p_end_str, p_bld->end_len); + p += p_bld->end_len; + } + + *p_len = (UINT16) (p - p_data); + return result; +} + +/******************************************************************************* +** +** Function bta_op_nextline +** +** Description Scan to beginning of next property text line. +** +** +** Returns Pointer to beginning of property or NULL if end of +** data reached. +** +*******************************************************************************/ +static UINT8 *bta_op_nextline(UINT8 *p, UINT8 *p_end, BOOLEAN qp) +{ +// btla-specific ++ + if (*p == '\r') + { + p--; + } +// btla-specific -- + + if ((p_end - p) > 3) + { + p_end -= 3; + while (p < p_end) + { + if (*(++p) == '\r') + { + if (*(p + 1) == '\n') + { + if (qp) + { + if (*(p - 1) == '=') + { + /* this is a soft break for quoted-printable*/ + continue; + } + } + + if ((*(p + 2) != ' ') && (*(p + 2) != '\t')) + { + return(p + 2); + } + } + } + } + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_op_scantok +** +** Description Scan a line for one or more tokens. +** +** +** Returns Pointer to token or NULL if end of data reached. +** +*******************************************************************************/ +static UINT8 *bta_op_scantok(UINT8 *p, UINT8 *p_end, const char *p_tok) +{ + int i; + UINT8 num_tok = strlen(p_tok); + + for (; p < p_end; p++) + { + for (i = 0; i < num_tok; i++) + { + if (*p == p_tok[i]) + { + return p; + } + } + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_op_scanstr +** +** Description Scan for a matching string. +** +** +** Returns Pointer to end of match or NULL if end of data reached. +** +*******************************************************************************/ +UINT8 *bta_op_scanstr(UINT8 *p, UINT8 *p_end, const char *p_str) +{ + int len = strlen(p_str); + + for (;;) + { + /* check for match */ + if (strncmp((char *) p, p_str, len) == 0) + { + p += len; + break; + } + /* no match; skip to next line, checking for end */ + else if ((p = bta_op_nextline(p, p_end, FALSE)) == NULL) + { + break; + } + } + return p; +} + +/******************************************************************************* +** +** Function bta_op_parse_obj +** +** Description Parse an object. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid data. +** BTA_OP_MEM if not enough memory to complete build. +** +*******************************************************************************/ +tBTA_OP_STATUS bta_op_parse_obj(const tBTA_OP_OBJ_TBL *p_prs, tBTA_OP_PROP *p_prop, + UINT8 *p_num_prop, UINT8 *p_data, UINT16 len) +{ + UINT32 j; + UINT8 *p_s, *p_e; + tBTA_OP_STATUS result = BTA_OP_OK; + UINT8 max_prop = *p_num_prop; + UINT8 *p_end = p_data + len; + UINT8 prop_name = 0; + BOOLEAN qp=FALSE; + + *p_num_prop = 0; + + /* sanity check length */ + if (len < p_prs->min_len) + { + return BTA_OP_FAIL; + } + + /* find beginning */ + if ((p_s = bta_op_scanstr(p_data, p_end, p_prs->p_begin_str)) == NULL) + { + return BTA_OP_FAIL; + } + + while (*p_num_prop < max_prop) + { + /* scan for next delimiter */ + if ((p_e = bta_op_scantok(p_s, p_end, ".;:")) == NULL) + { + break; + } + + /* deal with grouping delimiter */ + if (*p_e == '.') + { + p_s = p_e + 1; + if ((p_e = bta_op_scantok(p_s, p_end, ";:")) == NULL) + { + break; + } + } + + /* we found a property; see if it matches anything in our list */ + for (j = 1; j <= p_prs->p_tbl[0].len; j++) + { + if (bta_op_strnicmp(p_prs->p_tbl[j].p_name, (char *) p_s, + (p_prs->p_tbl[j].len - BTA_OP_PROP_OVHD)) == 0) + { + p_prop[*p_num_prop].name = prop_name = j; + p_prop[*p_num_prop].parameters = 0; + break; + } + } + + /* if not in our list we can't parse it; continue */ + if (j > p_prs->p_tbl[0].len) + { + if ((p_s = bta_op_nextline(p_e, p_end, FALSE)) == NULL) + { + break; + } + continue; + } + + /* now parse out all the parameters */ + if (*p_e == ';') + { + while ((*p_e == ';') || (*p_e == ',')) + { + p_s = p_e + 1; + + if ((p_e = bta_op_scantok(p_s, p_end, ",;:")) == NULL) + { + break; + } + + /* we found a parameter; see if it matches anything */ + + /* check for encoding */ + qp = FALSE; + if (bta_op_strnicmp(bta_op_encoding, (char *) p_s, BTA_OP_ENCODING_LEN) == 0) + { + p_s += BTA_OP_ENCODING_LEN; + for (j = 1; j <= BTA_OP_NUM_ENCODINGS; j++) + { + if (bta_op_strnicmp(bta_op_encodings[j].p_name, (char *) p_s, + (bta_op_encodings[j].len - BTA_OP_ENCODING_LEN - 1)) == 0) + { + if (j == BTA_OP_QP_IDX) + { + /* encoding = quoted-printable*/ + qp= TRUE; + } + p_prop[*p_num_prop].parameters |= j; + break; + } + } + } + /* check for charset */ + else if (bta_op_strnicmp(bta_op_charset, (char *) p_s, BTA_OP_CHARSET_LEN) == 0) + { + p_s += BTA_OP_CHARSET_LEN; + for (j = 1; j <= BTA_OP_NUM_CHARSETS; j++) + { + if (bta_op_strnicmp(bta_op_charsets[j].p_name, (char *) p_s, + (bta_op_charsets[j].len - BTA_OP_CHARSET_LEN - 1)) == 0) + { + p_prop[*p_num_prop].parameters |= j << 3; + break; + } + } + } + /* check for property-specific parameters */ + else if (p_prs->p_tbl[prop_name].p_param_tbl != NULL) + { + + /* Check for "TYPE=" */ + if (!bta_op_strnicmp((char *)p_s, bta_op_param_type_hdr, BTA_OP_PARAM_TYPE_HDR_LEN)) + { + p_s += BTA_OP_PARAM_TYPE_HDR_LEN; + } + + for (j = p_prs->p_tbl[prop_name].p_param_tbl[0].len; j > 0; j--) + { + if (bta_op_strnicmp(p_prs->p_tbl[prop_name].p_param_tbl[j].p_name, + (char *) p_s, (p_prs->p_tbl[prop_name].p_param_tbl[j].len - 1)) == 0) + { + p_prop[*p_num_prop].parameters |= ((UINT32) 1) << (j + 7); + break; + } + } + } + else + { + /* if this the start of the param */ + if (!p_prop[*p_num_prop].p_param) + p_prop[*p_num_prop].p_param = p_s; + if (*p_e == ':') + p_prop[*p_num_prop].param_len += (p_e - p_s); + else + p_prop[*p_num_prop].param_len += (p_e - p_s + 1); + } + } + } + + if (p_e == NULL) + { + break; + } + + /* go to start of next property */ + p_s = p_e + 1; + if ((p_e = bta_op_nextline(p_s, p_end, qp)) == NULL) + { + break; + } + + /* save property info */ + p_prop[*p_num_prop].p_data = p_s; + p_prop[*p_num_prop].len = (UINT16) (p_e - p_s - 2); +// btla-specific ++ + if (p_prop[*p_num_prop].len) + { + (*p_num_prop)++; + } +// btla-specific -- + p_s = p_e; + } + return result; +} + diff --git a/bta/op/bta_op_fmt.h b/bta/op/bta_op_fmt.h new file mode 100644 index 0000000..29bb40c --- /dev/null +++ b/bta/op/bta_op_fmt.h @@ -0,0 +1,92 @@ +/***************************************************************************** +** +** Name: bta_op_fmt.h +** +** Description: This is the interface file for common functions and data +** types used by the OPP object formatting functions. +** +** Copyright (c) 2003, Widcomm Inc., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_OP_FMT_H +#define BTA_OP_FMT_H + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_OP_PROP_OVHD 3 + +/***************************************************************************** +** Data types +*****************************************************************************/ + +enum { + BTA_OP_FMT_NONE=0, + BTA_OP_FMT_VCARD21, + BTA_OP_FMT_VCARD30, + BTA_OP_FMT_VCAL10, + BTA_OP_FMT_VNOTE11 +}; + +/*Supported formats */ +typedef UINT8 tBTA_OP_SUP_FMT; + +typedef struct +{ + const char *p_name; + UINT8 len; +} tBTA_OP_PARAM; + +typedef struct +{ + const char *p_name; + const tBTA_OP_PARAM *p_param_tbl; + UINT8 len; +} tBTA_OP_PROP_TBL; + + +typedef struct +{ + const UINT32 *p_prop_filter_mask; + UINT8 len; +} tBTA_OP_PROP_FILTER_MASK_TBL; + +typedef struct +{ + const tBTA_OP_PROP_TBL *p_tbl; + tBTA_OP_SUP_FMT fmt; + const char *p_begin_str; + const char *p_end_str; + UINT8 begin_len; + UINT8 end_len; + UINT8 min_len; + const tBTA_OP_PROP_FILTER_MASK_TBL *p_prop_filter_mask_tbl; +} tBTA_OP_OBJ_TBL; + +typedef struct +{ + const char *media_name; + UINT8 len; +} tBTA_OP_PROP_MEDIA; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +extern tBTA_OP_STATUS bta_op_build_obj(const tBTA_OP_OBJ_TBL *p_bld, + UINT8 *p_data, UINT16 *p_len, + tBTA_OP_PROP *p_prop, UINT8 num_prop); + +extern tBTA_OP_STATUS bta_op_parse_obj(const tBTA_OP_OBJ_TBL *p_prs, + tBTA_OP_PROP *p_prop, UINT8 *p_num_prop, + UINT8 *p_data, UINT16 len); +extern tBTA_OP_STATUS bta_op_get_property_by_name(const tBTA_OP_PROP_TBL *p_tbl, UINT8 *p_name, + tBTA_OP_PROP *p_prop, UINT8 num_prop, UINT8 *p_data, + UINT16 *p_len); +extern UINT8 *bta_op_scanstr(UINT8 *p, UINT8 *p_end, const char *p_str); +extern void bta_op_set_prop_filter_mask(UINT32 mask); + +#endif /* BTA_OP_FMT_H */ + diff --git a/bta/op/bta_op_vcal.c b/bta/op/bta_op_vcal.c new file mode 100644 index 0000000..79aef02 --- /dev/null +++ b/bta/op/bta_op_vcal.c @@ -0,0 +1,158 @@ +/***************************************************************************** +** +** Name: bta_op_vcal.c +** +** Description: This file contains functions for parsing and building +** vCal objects. +** +** Copyright (c) 2003, Widcomm Inc., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bta_op_api.h" +#include "bta_op_fmt.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_OP_TODO_BEGIN_LEN 43 +#define BTA_OP_TODO_END_LEN 26 + +#define BTA_OP_TODO_MIN_LEN (BTA_OP_TODO_BEGIN_LEN + BTA_OP_TODO_END_LEN) + +#define BTA_OP_EVENT_BEGIN_LEN 44 +#define BTA_OP_EVENT_END_LEN 27 + +#define BTA_OP_EVENT_MIN_LEN (BTA_OP_EVENT_BEGIN_LEN + BTA_OP_EVENT_END_LEN) + +#define BTA_OP_VCAL_BEGIN_LEN 17 +#define BTA_OP_VCAL_END_LEN 15 +#define BTA_OP_VCAL_MIN_LEN (BTA_OP_VCAL_BEGIN_LEN + BTA_OP_VCAL_END_LEN) +#define BTA_OP_BEGIN_OFFSET 30 + +const char bta_op_vcal_begin[] = "BEGIN:VCALENDAR\r\n"; + +const char bta_op_todo_begin[] = "BEGIN:VCALENDAR\r\nVERSION:1.0\r\nBEGIN:VTODO\r\n"; + +const char bta_op_todo_end[] = "END:VTODO\r\nEND:VCALENDAR\r\n"; + +const char bta_op_event_begin[] = "BEGIN:VCALENDAR\r\nVERSION:1.0\r\nBEGIN:VEVENT\r\n"; + +const char bta_op_event_end[] = "END:VEVENT\r\nEND:VCALENDAR\r\n"; + +const tBTA_OP_PROP_TBL bta_op_vcal_tbl[] = +{ + {NULL, NULL, 11}, /* Number of elements in array */ + {"CATEGORIES", NULL, 13}, /* BTA_OP_VCAL_CATEGORIES */ + {"COMPLETED", NULL, 12}, /* BTA_OP_VCAL_COMPLETED */ + {"DESCRIPTION", NULL, 14}, /* BTA_OP_VCAL_DESCRIPTION */ + {"DTEND", NULL, 8}, /* BTA_OP_VCAL_DTEND */ + {"DTSTART", NULL, 10}, /* BTA_OP_VCAL_DTSTART */ + {"DUE", NULL, 6}, /* BTA_OP_VCAL_DUE */ + {"LOCATION", NULL, 11}, /* BTA_OP_VCAL_LOCATION */ + {"PRIORITY", NULL, 11}, /* BTA_OP_VCAL_PRIORITY */ + {"STATUS", NULL, 9}, /* BTA_OP_VCAL_STATUS */ + {"SUMMARY", NULL, 10}, /* BTA_OP_VCAL_SUMMARY */ + {"X-IRMC-LUID", NULL, 14} /* BTA_OP_VCAL_LUID */ +}; + +const tBTA_OP_OBJ_TBL bta_op_todo_bld = +{ + bta_op_vcal_tbl, + BTA_OP_FMT_VCAL10, + bta_op_todo_begin, + bta_op_todo_end, + BTA_OP_TODO_BEGIN_LEN, + BTA_OP_TODO_END_LEN, + BTA_OP_TODO_MIN_LEN +}; + +const tBTA_OP_OBJ_TBL bta_op_event_bld = +{ + bta_op_vcal_tbl, + BTA_OP_FMT_VCAL10, + bta_op_event_begin, + bta_op_event_end, + BTA_OP_EVENT_BEGIN_LEN, + BTA_OP_EVENT_END_LEN, + BTA_OP_EVENT_MIN_LEN +}; + +const tBTA_OP_OBJ_TBL bta_op_vcal_prs = +{ + bta_op_vcal_tbl, + BTA_OP_FMT_VCAL10, + bta_op_vcal_begin, + NULL, + BTA_OP_VCAL_BEGIN_LEN, + BTA_OP_VCAL_END_LEN, + BTA_OP_VCAL_MIN_LEN +}; + +/******************************************************************************* +** +** Function BTA_OpBuildCal +** +** Description Build a vCal 1.0 object. The input to this function is an +** array of vCaalproperties and a pointer to memory to store +** the card. The output is a formatted vCal. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete build. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpBuildCal(UINT8 *p_cal, UINT16 *p_len, tBTA_OP_PROP *p_prop, + UINT8 num_prop, tBTA_OP_VCAL vcal_type) +{ + tBTA_OP_OBJ_TBL *p_bld; + + if (vcal_type == BTA_OP_VCAL_EVENT) + { + p_bld = (tBTA_OP_OBJ_TBL *) &bta_op_event_bld; + } + else + { + p_bld = ( tBTA_OP_OBJ_TBL *) &bta_op_todo_bld; + } + + return bta_op_build_obj(p_bld, p_cal, p_len, p_prop, num_prop); +} + +/******************************************************************************* +** +** Function BTA_OpParseCal +** +** Description Parse a vCal object. The input to this function is a +** pointer to vCal data. The output is an array of parsed +** vCal properties. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete parsing. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpParseCal(tBTA_OP_PROP *p_prop, UINT8 *p_num_prop, UINT8 *p_cal, + UINT16 len, tBTA_OP_VCAL *p_vcal_type) +{ + if (bta_op_scanstr(p_cal, (p_cal + len), &bta_op_todo_begin[BTA_OP_BEGIN_OFFSET]) != NULL) + { + *p_vcal_type = BTA_OP_VCAL_TODO; + } + else if (bta_op_scanstr(p_cal, (p_cal + len), &bta_op_event_begin[BTA_OP_BEGIN_OFFSET]) != NULL) + { + *p_vcal_type = BTA_OP_VCAL_EVENT; + } + else + { + *p_num_prop = 0; + return BTA_OP_FAIL; + } + + return bta_op_parse_obj(&bta_op_vcal_prs, p_prop, p_num_prop, p_cal, len); +} + diff --git a/bta/op/bta_op_vcard.c b/bta/op/bta_op_vcard.c new file mode 100644 index 0000000..6a278ba --- /dev/null +++ b/bta/op/bta_op_vcard.c @@ -0,0 +1,310 @@ +/***************************************************************************** +** +** Name: bta_op_vcard.c +** +** Description: This file contains functions for parsing and building +** vCard objects. +** +** Copyright (c) 2003, Widcomm Inc., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bta_op_api.h" +#include "bta_op_fmt.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_OP_VCARD_BEGIN_LEN 26 +#define BTA_OP_VCARD_END_LEN 11 + +#define BTA_OP_VCARD_MIN_LEN (BTA_OP_VCARD_BEGIN_LEN + BTA_OP_VCARD_END_LEN) + +const char bta_op_vcard_prs_begin[] = "BEGIN:VCARD\r\n"; + +const char bta_op_vcard_21_begin[] = "BEGIN:VCARD\r\nVERSION:2.1\r\n"; + +const char bta_op_vcard_30_begin[] = "BEGIN:VCARD\r\nVERSION:3.0\r\n"; + +const char bta_op_vcard_end[] = "END:VCARD\r\n"; + +const tBTA_OP_PARAM bta_op_vcard_adr[] = +{ + {NULL, 6}, /* Number of elements in array */ + {"DOM", 4}, /* BTA_OP_ADR_DOM */ + {"INTL", 5}, /* BTA_OP_ADR_INTL */ + {"POSTAL", 7}, /* BTA_OP_ADR_POSTAL */ + {"PARCEL", 7}, /* BTA_OP_ADR_PARCEL */ + {"HOME", 5}, /* BTA_OP_ADR_HOME */ + {"WORK", 5} /* BTA_OP_ADR_WORK */ +}; + +const tBTA_OP_PARAM bta_op_vcard_email[] = +{ + {NULL, 3}, /* Number of elements in array */ + {"PREF", 5}, /* BTA_OP_EMAIL_PREF */ + {"INTERNET", 9}, /* BTA_OP_EMAIL_INTERNET */ + {"X400", 5} /* BTA_OP_EMAIL_X400 */ +}; + +const tBTA_OP_PARAM bta_op_vcard_tel[] = +{ + {NULL, 8}, /* Number of elements in array */ + {"PREF", 5}, /* BTA_OP_TEL_PREF */ + {"WORK", 5}, /* BTA_OP_TEL_WORK */ + {"HOME", 5}, /* BTA_OP_TEL_HOME */ + {"VOICE", 6}, /* BTA_OP_TEL_VOICE */ + {"FAX", 4}, /* BTA_OP_TEL_FAX */ + {"MSG", 4}, /* BTA_OP_TEL_MSG */ + {"CELL", 5}, /* BTA_OP_TEL_CELL */ + {"PAGER", 6} /* BTA_OP_TEL_PAGER */ +}; + +const tBTA_OP_PARAM bta_op_vcard_photo[] = +{ + {NULL, 4}, /* Number of elements in array */ + {"VALUE=URI", 10}, /* BTA_OP_PHOTO_VALUE_URI */ + {"VALUE=URL", 10}, /* BTA_OP_PHOTO_VALUE_URL */ + {"JPEG", 5}, /* BTA_OP_PHOTO_TYPE_JPEG */ + {"GIF", 4} /* BTA_OP_PHOTO_TYPE_GIF */ +}; + +const tBTA_OP_PARAM bta_op_vcard_sound[] = +{ + {NULL, 4}, /* Number of elements in array */ + {"VALUE=URI", 10}, /* BTA_OP_SOUND_VALUE_URI */ + {"VALUE=URL", 10}, /* BTA_OP_SOUND_VALUE_URL */ + {"BASIC", 6}, /* BTA_OP_SOUND_TYPE_BASIC */ + {"WAVE", 5} /* BTA_OP_SOUND_TYPE_WAVE */ +}; + +const tBTA_OP_PROP_TBL bta_op_vcard_tbl[] = +{ + {NULL, NULL, 15}, /* Number of elements in array */ + {"ADR", bta_op_vcard_adr, 6}, /* BTA_OP_VCARD_ADR */ + {"EMAIL", bta_op_vcard_email, 8}, /* BTA_OP_VCARD_EMAIL */ + {"FN", NULL, 5}, /* BTA_OP_VCARD_FN */ + {"NOTE", NULL, 7}, /* BTA_OP_VCARD_NOTE */ + {"NICKNAME", NULL, 11}, /* BTA_OP_VACRD_NICKNAME */ + {"N", NULL, 4}, /* BTA_OP_VCARD_N */ + {"ORG", NULL, 6}, /* BTA_OP_VCARD_ORG */ + {"TEL", bta_op_vcard_tel, 6}, /* BTA_OP_VCARD_TEL */ + {"TITLE", NULL, 8}, /* BTA_OP_VCARD_TITLE */ + {"URL", NULL, 6}, /* BTA_OP_VCARD_URL */ + {"X-IRMC-LUID", NULL, 14}, /* BTA_OP_VNOTE_LUID */ + {"BDAY", NULL, 7}, /* BTA_OP_VCARD_BDAY */ + {"PHOTO", bta_op_vcard_photo, 8}, /* BTA_OP_VCARD_PHOTO */ + {"SOUND", bta_op_vcard_sound, 8}, /* BTA_OP_VCARD_SOUND */ + {"X-IRMC-CALL-DATETIME", NULL, 23} /* BTA_OP_VCARD_CALL */ +}; + +const UINT32 bta_op_vcard_prop_filter_mask[] = +{ +/* table index should be the same as the prop table above */ + BTA_OP_FILTER_ALL, + BTA_OP_FILTER_ADR, + BTA_OP_FILTER_EMAIL, + BTA_OP_FILTER_FN, + BTA_OP_FILTER_NOTE, + BTA_OP_FILTER_NICKNAME, + BTA_OP_FILTER_N, + BTA_OP_FILTER_ORG, + BTA_OP_FILTER_TEL, + BTA_OP_FILTER_TITLE, + BTA_OP_FILTER_URL, + BTA_OP_FILTER_UID, + BTA_OP_FILTER_BDAY, + BTA_OP_FILTER_PHOTO, + BTA_OP_FILTER_SOUND, + BTA_OP_FILTER_TIME_STAMP +}; + +const tBTA_OP_PROP_FILTER_MASK_TBL bta_op_vcard_prop_filter_mask_tbl = +{ + bta_op_vcard_prop_filter_mask, + 15 +}; + +const tBTA_OP_OBJ_TBL bta_op_vcard_21_bld = +{ + bta_op_vcard_tbl, + BTA_OP_FMT_VCARD21, + bta_op_vcard_21_begin, + bta_op_vcard_end, + BTA_OP_VCARD_BEGIN_LEN, + BTA_OP_VCARD_END_LEN, + BTA_OP_VCARD_MIN_LEN, + &bta_op_vcard_prop_filter_mask_tbl +}; + +const tBTA_OP_OBJ_TBL bta_op_vcard_30_bld = +{ + bta_op_vcard_tbl, + BTA_OP_FMT_VCARD30, + bta_op_vcard_30_begin, + bta_op_vcard_end, + BTA_OP_VCARD_BEGIN_LEN, + BTA_OP_VCARD_END_LEN, + BTA_OP_VCARD_MIN_LEN, + &bta_op_vcard_prop_filter_mask_tbl +}; + +const tBTA_OP_OBJ_TBL bta_op_vcard_21_prs = +{ + bta_op_vcard_tbl, + BTA_OP_FMT_VCARD21, + bta_op_vcard_prs_begin, + bta_op_vcard_end, + BTA_OP_VCARD_BEGIN_LEN, + BTA_OP_VCARD_END_LEN, + BTA_OP_VCARD_MIN_LEN, + NULL +}; + +const tBTA_OP_OBJ_TBL bta_op_vcard_30_prs = +{ + bta_op_vcard_tbl, + BTA_OP_FMT_VCARD30, + bta_op_vcard_prs_begin, + bta_op_vcard_end, + BTA_OP_VCARD_BEGIN_LEN, + BTA_OP_VCARD_END_LEN, + BTA_OP_VCARD_MIN_LEN, + NULL +}; + + +/******************************************************************************* +** +** Function bta_op_get_card_fmt +** +** Description Finds the vCard format contained in buffer pointed by p_card +** +** +** Returns Vcard Format BTA_OP_VCARD21_FMT/BTA_OP_VCARD30_FMT else +** BTA_OP_OTHER_FMT +** +*******************************************************************************/ +static tBTA_OP_SUP_FMT bta_op_get_card_fmt(UINT8 *p_data, UINT16 len) +{ + UINT8 *p_end = p_data + len; + + if (bta_op_scanstr(p_data, p_end, bta_op_vcard_21_begin) != NULL) + { + return BTA_OP_FMT_VCARD21; + } + else if (bta_op_scanstr(p_data, p_end, bta_op_vcard_30_begin) != NULL) + { + return BTA_OP_FMT_VCARD30; + } + else + { + return BTA_OP_FMT_NONE; + } +} + +/******************************************************************************* +** +** Function BTA_OpBuildCard +** +** Description Build a vCard object. The input to this function is +** requested format(2.1/3.0), an array of vCard properties +** and a pointer to memory to store the card. +** The output is a formatted vCard. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete build. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpBuildCard(UINT8 *p_card, UINT16 *p_len, tBTA_OP_FMT fmt, + tBTA_OP_PROP *p_prop, UINT8 num_prop) +{ + if(fmt == BTA_OP_VCARD21_FMT) + { + return bta_op_build_obj(&bta_op_vcard_21_bld, p_card, p_len, p_prop, num_prop); + } + else if(fmt == BTA_OP_VCARD30_FMT) + { + return bta_op_build_obj(&bta_op_vcard_30_bld, p_card, p_len, p_prop, num_prop); + } + else + { + *p_len = 0; + return BTA_OP_FAIL; + } +} + +/******************************************************************************* +** +** Function BTA_OpSetCardPropFilterMask +** +** Description Set Property Filter Mask +** +** +** Returns +** +*******************************************************************************/ +void BTA_OpSetCardPropFilterMask(UINT32 mask) +{ + bta_op_set_prop_filter_mask(mask); + return; +} + +/******************************************************************************* +** +** Function BTA_OpParseCard +** +** Description Parse a vCard 2.1 object. The input to this function is +** a pointer to vCard data. The output is an array of parsed +** vCard properties. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete parsing. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpParseCard(tBTA_OP_PROP *p_prop, UINT8 *p_num_prop, + UINT8 *p_card, UINT16 len) +{ + tBTA_OP_SUP_FMT fmt = bta_op_get_card_fmt(p_card, len); + + if (fmt == BTA_OP_FMT_VCARD21) + { + return bta_op_parse_obj(&bta_op_vcard_21_prs, p_prop, p_num_prop, p_card, len); + } + else if(fmt == BTA_OP_FMT_VCARD30) + { + return bta_op_parse_obj(&bta_op_vcard_30_prs, p_prop, p_num_prop, p_card, len); + } + else + { + *p_num_prop = 0; + return BTA_OP_FAIL; + } +} + +/******************************************************************************* +** +** Function BTA_OpGetCardProperty +** +** Description Get Card property value by name. The input to this function is +** property name. The output is property value and len +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpGetCardProperty(UINT8 *p_value, UINT16 *p_len, tBTA_OP_PROP *p_prop, + UINT8 num_prop, UINT8 *p_name) +{ + return bta_op_get_property_by_name(bta_op_vcard_tbl, p_name, + p_prop, num_prop, p_value, p_len); +} + + diff --git a/bta/op/bta_op_vnote.c b/bta/op/bta_op_vnote.c new file mode 100644 index 0000000..ff1c015 --- /dev/null +++ b/bta/op/bta_op_vnote.c @@ -0,0 +1,99 @@ +/***************************************************************************** +** +** Name: bta_op_vnote.c +** +** Description: This file contains functions for parsing and building +** vNote objects. +** +** Copyright (c) 2003, Widcomm Inc., All Rights Reserved. +** Widcomm Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bta_op_api.h" +#include "bta_op_fmt.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_OP_VNOTE_BEGIN_LEN 26 +#define BTA_OP_VNOTE_END_LEN 11 + +#define BTA_OP_VNOTE_MIN_LEN (BTA_OP_VNOTE_BEGIN_LEN + BTA_OP_VNOTE_END_LEN) + +const char bta_op_vnote_prs_begin[] = "BEGIN:VNOTE\r\n"; + +const char bta_op_vnote_begin[] = "BEGIN:VNOTE\r\nVERSION:1.1\r\n"; + +const char bta_op_vnote_end[] = "END:VNOTE\r\n"; + +const tBTA_OP_PROP_TBL bta_op_vnote_tbl[] = +{ + {NULL, NULL, 2}, /* Number of elements in array */ + {"BODY", NULL, 7}, /* BTA_OP_VNOTE_BODY */ + {"X-IRMC-LUID", NULL, 14} /* BTA_OP_VNOTE_LUID */ +}; + +const tBTA_OP_OBJ_TBL bta_op_vnote_bld = +{ + bta_op_vnote_tbl, + BTA_OP_FMT_VNOTE11, + bta_op_vnote_begin, + bta_op_vnote_end, + BTA_OP_VNOTE_BEGIN_LEN, + BTA_OP_VNOTE_END_LEN, + BTA_OP_VNOTE_MIN_LEN +}; + +const tBTA_OP_OBJ_TBL bta_op_vnote_prs = +{ + bta_op_vnote_tbl, + BTA_OP_FMT_VNOTE11, + bta_op_vnote_prs_begin, + bta_op_vnote_end, + BTA_OP_VNOTE_BEGIN_LEN, + BTA_OP_VNOTE_END_LEN, + BTA_OP_VNOTE_MIN_LEN +}; + +/******************************************************************************* +** +** Function BTA_OpBuildNote +** +** Description Build a vNote object. The input to this function is an +** array of vNote properties and a pointer to memory to store +** the card. The output is a formatted vNote. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete build. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpBuildNote(UINT8 *p_note, UINT16 *p_len, tBTA_OP_PROP *p_prop, + UINT8 num_prop) +{ + return bta_op_build_obj(&bta_op_vnote_bld, p_note, p_len, p_prop, num_prop); +} + +/******************************************************************************* +** +** Function BTA_OpParseNote +** +** Description Parse a vNote object. The input to this function is a +** pointer to vNote data. The output is an array of parsed +** vNote properties. +** +** +** Returns BTA_OP_OK if operation successful. +** BTA_OP_FAIL if invalid property data. +** BTA_OP_MEM if not enough memory to complete parsing. +** +*******************************************************************************/ +tBTA_OP_STATUS BTA_OpParseNote(tBTA_OP_PROP *p_prop, UINT8 *p_num_prop, UINT8 *p_note, + UINT16 len) +{ + return bta_op_parse_obj(&bta_op_vnote_prs, p_prop, p_num_prop, p_note, len); +} + diff --git a/bta/op/bta_opc_act.c b/bta/op/bta_opc_act.c new file mode 100644 index 0000000..cf4780d --- /dev/null +++ b/bta/op/bta_opc_act.c @@ -0,0 +1,1017 @@ +/***************************************************************************** +** +** Name: bta_opc_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 <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_op_api.h" +#include "bta_opc_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_OPC_DISC_SIZE 450 + + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +#if BTA_OPC_DEBUG == TRUE +static char *opc_obx_evt_code(tOBX_EVENT evt_code); +#endif + +static void bta_opc_sdp_cback(UINT16 status); + + +/***************************************************************************** +** Action Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_opc_enable +** +** Description Handle an api enable event. This function enables the OP +** Client by opening an Obex/Rfcomm channel with a peer device. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_enable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + + /* store parameters */ + p_cb->p_cback = p_data->api_enable.p_cback; + p_cb->sec_mask = p_data->api_enable.sec_mask; + p_cb->app_id = p_data->api_enable.app_id; + p_cb->srm = p_data->api_enable.srm; + p_cb->single_op = p_data->api_enable.single_op; + p_cb->fd = BTA_FS_INVALID_FD; + + /* callback with enable event */ + (*p_cb->p_cback)(BTA_OPC_ENABLE_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_opc_init_push +** +** Description Push an object to the OPP server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_init_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + p_cb->status = BTA_OPC_FAIL; + p_cb->exch_status = BTA_OPC_OK; + + if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + p_cb->to_do = BTA_OPC_PUSH_MASK; + p_cb->format = p_data->api_push.format; + BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_data->api_push.p_name, p_bta_fs_cfg->max_path_len); + p_cb->p_name[p_bta_fs_cfg->max_path_len] = '\0'; + } + else + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL); +} + +/******************************************************************************* +** +** Function bta_opc_init_pull +** +** Description Pull an object off the server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_init_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + p_cb->status = BTA_OPC_FAIL; + p_cb->exch_status = BTA_OPC_OK; + + if ((p_cb->p_name = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_file_len + + p_bta_fs_cfg->max_path_len + 2))) != NULL) + { + p_cb->p_rcv_path = p_cb->p_name + p_bta_fs_cfg->max_file_len + 1; + p_cb->to_do = BTA_OPC_PULL_MASK; + p_cb->first_get_pkt = TRUE; + BCM_STRNCPY_S(p_cb->p_rcv_path, p_bta_fs_cfg->max_path_len+1, p_data->api_pull.p_path, p_bta_fs_cfg->max_path_len); + p_cb->p_rcv_path[p_bta_fs_cfg->max_path_len] = '\0'; + } + else + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL); +} + +/******************************************************************************* +** +** Function bta_opc_init_exch +** +** Description Exchange business cards with a server. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_init_exch(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + p_cb->status = BTA_OPC_FAIL; + p_cb->exch_status = BTA_OPC_OK; + + /* Need room to hold the receive path, along with path and file name to push */ + if ((p_cb->p_name = + (char *)GKI_getbuf((UINT16)((p_bta_fs_cfg->max_path_len + 1) * 2))) != NULL) + { + p_cb->p_rcv_path = p_cb->p_name + p_bta_fs_cfg->max_path_len + 1; + p_cb->to_do = BTA_OPC_PULL_MASK | BTA_OPC_PUSH_MASK; + p_cb->first_get_pkt = TRUE; + BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, p_data->api_exch.p_send, p_bta_fs_cfg->max_path_len); + p_cb->p_name[p_bta_fs_cfg->max_path_len] = '\0'; + BCM_STRNCPY_S(p_cb->p_rcv_path, p_bta_fs_cfg->max_path_len+1, p_data->api_exch.p_rcv_path, p_bta_fs_cfg->max_path_len); + p_cb->p_rcv_path[p_bta_fs_cfg->max_path_len] = '\0'; + } + else + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL); +} + +/******************************************************************************* +** +** Function bta_opc_trans_cmpl +** +** Description push/pull complete +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_trans_cmpl(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBJECT param; + tBTA_OPC_EVT evt = BTA_OPC_OBJECT_EVT; + tBTA_FS_CO_STATUS status; + + if (p_data) + { + p_cb->status = bta_opc_convert_obx_to_opc_status(p_data->obx_evt.rsp_code); + } + else + { + /* some action functions send the event to SM with NULL p_data */ + p_cb->status = BTA_OPC_FAIL; + } + + if (p_cb->obx_oper == OPC_OP_PUSH_OBJ) + evt = BTA_OPC_OBJECT_PSHD_EVT; + + /* rearrange the code a little bit to make sure p_cb->status is for the current op + * (previously, we might use the ststus from the PUSH op, if this is an exchange card) */ + param.status = p_cb->status; + + /* If exchange, and push received an error use this error */ + if (p_cb->exch_status != BTA_OPC_OK) + param.status = p_cb->exch_status; + + /* Notify appl the result of the pull or push */ + param.p_name = p_cb->p_name; + p_cb->p_cback(evt, (tBTA_OPC *)¶m); + + /* 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 vCard operation */ + if (p_cb->obx_oper == OPC_OP_PULL_OBJ && p_cb->status != BTA_OPC_OK) + { + status = bta_fs_co_unlink(p_cb->p_name, p_cb->app_id); + APPL_TRACE_WARNING2("OPC: Remove ABORTED Get File Operation [%s], status 0x%02x", + p_cb->p_name, status); + } + } + + utl_freebuf((void**)&p_cb->p_name); + + p_cb->obx_oper = OPC_OP_NONE; + +} + +/******************************************************************************* +** +** Function bta_opc_ci_write +** +** Description Continue with the current write operation +** (Get File processing) +** +** Returns void +** +*******************************************************************************/ +void bta_opc_ci_write(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_OPC_PROGRESS 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 == OPC_OP_PULL_OBJ) + { + if (p_data->write_evt.status == BTA_FS_CO_OK) + { + param.bytes = p_obx->offset; + param.obj_size = p_cb->obj_size; + param.operation = BTA_OP_OPER_PULL; + p_cb->p_cback(BTA_OPC_PROGRESS_EVT, (tBTA_OPC *)¶m); + + /* Send another Get request if not finished */ + if (!p_obx->final_pkt) + { + /* Free current packet and send a new request */ + bta_opc_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_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_opc_ci_read +** +** Description Handles the response to a read call-out request. +** This is called within the OBX get object request. The +** operation has completed, send the OBX packet out. +** +** Returns void +** +*******************************************************************************/ +void bta_opc_ci_read(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FS_CI_READ_EVT *p_revt = &p_data->read_evt; + tBTA_OPC_PROGRESS param; + BOOLEAN is_final; + + p_cb->cout_active = FALSE; + + /* Process read call-in event if operation is still active */ + if (p_cb->obx_oper == OPC_OP_PUSH_OBJ) + { + if (p_revt->status != BTA_FS_CO_OK && p_revt->status != BTA_FS_CO_EOF) + { + p_data->obx_evt.rsp_code = OBX_RSP_FAILED; +/* if abort added to OPC use -> bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data); */ + bta_opc_sm_execute(p_cb, BTA_OPC_API_CLOSE_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.bytes = p_revt->num_read; + param.obj_size = p_cb->obj_size; + param.operation = BTA_OP_OPER_PUSH; + p_cb->p_cback(BTA_OPC_PROGRESS_EVT, (tBTA_OPC *)¶m); + } + } +} + +/******************************************************************************* +** +** Function bta_opc_ci_open +** +** Description Continue with the current file open operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_ci_open(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt; + UINT8 rsp_code = OBX_RSP_FAILED; + + p_cb->cout_active = FALSE; + + /* 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 (p_cb->obx_oper == OPC_OP_PUSH_OBJ) + { + p_cb->obj_size = p_open->file_size; + + rsp_code = bta_opc_send_put_req(p_cb, TRUE); + } + else if (p_cb->obx_oper == OPC_OP_PULL_OBJ) + { + rsp_code = OBX_RSP_OK; + + /* Initiate the first OBX GET request */ + p_obx->offset = 0; + + /* Continue processing GET rsp */ + bta_opc_cont_get_rsp(p_cb); + } + } + 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_opc_sm_execute(p_cb, BTA_OPC_API_CLOSE_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_opc_obx_conn_rsp +** +** Description Process the OBX connect event. +** If OPP service, get directory listing. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_obx_conn_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt; + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); + + p_cb->peer_mtu = p_data->obx_evt.param.conn.mtu; + + /* inform role manager */ + bta_sys_conn_open( BTA_ID_OPC ,p_cb->app_id, bta_opc_cb.bd_addr); + + p_cb->p_cback(BTA_OPC_OPEN_EVT, NULL); + + /* start the first operation. For card exchange PUSH is done first */ + if(p_cb->to_do & BTA_OPC_PUSH_MASK) + bta_opc_start_push(p_cb); + else + bta_opc_send_get_req(p_cb); +} + +/******************************************************************************* +** +** Function bta_opc_obx_put_rsp +** +** Description Process the OBX file put and delete file/folder events +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_obx_put_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_OPC_OBJECT param; + + p_cb->req_pending = FALSE; + APPL_TRACE_DEBUG1("bta_opc_obx_put_rsp to_do 0x%02x",p_cb->to_do); + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); + + if (p_cb->obx_oper == OPC_OP_PUSH_OBJ) + { + /* If not finished with Put, start another read */ + if (p_evt->rsp_code == OBX_RSP_CONTINUE) + bta_opc_send_put_req(p_cb, FALSE); + + /* Start the Pull if this is card exchange */ + else if (p_cb->to_do & BTA_OPC_PULL_MASK) + { + /* Close the current file and initiate a pull vcard */ + bta_fs_co_close(p_cb->fd, p_cb->app_id); + p_cb->fd = BTA_FS_INVALID_FD; + + /* If error occurred during push save it */ + if (p_evt->rsp_code != OBX_RSP_OK) + p_cb->exch_status = BTA_OPC_FAIL; + + /* Notify application with status of push operation */ + param.status = p_cb->exch_status; + param.p_name = p_cb->p_name; + p_cb->p_cback(BTA_OPC_OBJECT_PSHD_EVT, (tBTA_OPC *)¶m); + + /* Initiate the Pull operation */ + bta_opc_send_get_req(p_cb); + } + else /* Finished or an error occurred */ + { + p_data->obx_evt.rsp_code = p_evt->rsp_code; + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_opc_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_opc_obx_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + BOOLEAN free_pkt = FALSE; + + p_obx->final_pkt = (p_evt->rsp_code == OBX_RSP_OK) ? TRUE : FALSE; + p_obx->p_pkt = p_evt->p_pkt; + p_obx->rsp_code = p_evt->rsp_code; + p_cb->req_pending = FALSE; + + if (p_cb->obx_oper == OPC_OP_PULL_OBJ) + { + /* Open file for writing */ + if (p_cb->first_get_pkt == TRUE) + { + p_cb->first_get_pkt = FALSE; + free_pkt = bta_opc_proc_get_rsp(p_cb, p_data); + } + else /* Continuation of the object transfer */ + bta_opc_cont_get_rsp(p_cb); + } + else + free_pkt = TRUE; + + if (free_pkt) /* Release the OBX response packet */ + utl_freebuf((void**)&p_obx->p_pkt); +} + +/******************************************************************************* +** +** Function bta_opc_initialize +** +** Description Initialize the control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_initialize(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_FS_CO_STATUS status; + + 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 get vCard operation */ + if (p_cb->obx_oper == OPC_OP_PULL_OBJ && p_cb->status != BTA_OPC_OK) + { + status = bta_fs_co_unlink(p_cb->p_name, p_cb->app_id); + APPL_TRACE_WARNING2("OPC: Remove ABORTED Get File Operation [%s], status 0x%02x", + p_cb->p_name, status); + } + } + + utl_freebuf((void**)&p_cb->p_name); + + /* Clean up control block */ + p_cb->obx_oper = OPC_OP_NONE; + p_cb->req_pending = FALSE; + p_cb->sdp_pending = FALSE; + p_cb->to_do = 0; + p_cb->p_rcv_path = NULL; + p_cb->first_get_pkt = FALSE; + + if (p_cb->disabling) + { + p_cb->disabling = FALSE; + bta_opc_sm_execute(p_cb, BTA_OPC_DISABLE_CMPL_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_opc_stop_client +** +** Description Stop OBX client. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_stop_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + if (!p_cb->sdp_pending) + { +// btla-specific ++ +#if defined (BTA_OPC_SENDING_ABORT) && (BTA_OPC_SENDING_ABORT == TRUE) + APPL_TRACE_WARNING3("bta_opc_stop_client p_cb->req_pending = %d, p_cb->sdp_pending = %d,handle = %d", + p_cb->req_pending, p_cb->sdp_pending,p_cb->obx_handle); + /* Abort an active request */ + if (p_cb->req_pending) + OBX_AbortReq(p_cb->obx_handle, (BT_HDR *)NULL); +#endif +// btla-specific -- + /* do not free p_cb->obx.p_pkt here, just in case cout_active. + * bta_opc_close_complete would handle it */ + OBX_DisconnectReq(p_cb->obx_handle, NULL); + } +} + +/******************************************************************************* +** +** Function bta_opc_close +** +** Description If not waiting for a call-in function, complete the closing +** of the channel. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + /* finished if not waiting on a call-in function */ + if (!p_cb->cout_active) + bta_opc_sm_execute(p_cb, BTA_OPC_CLOSE_CMPL_EVT, p_data); +} + +/******************************************************************************* +** +** Function bta_opc_start_client +** +** Description Start an OPP operation. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_start_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + tOBX_STATUS status; + BOOLEAN srm = p_cb->srm; + + /* Allocate an OBX packet */ + if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(OBX_HANDLE_NULL, OBX_MAX_MTU)) != NULL) + { + status = OBX_AllocSession (NULL, p_data->sdp_ok.scn, &p_data->sdp_ok.psm, + bta_opc_obx_cback, &p_cb->obx_handle); + + /* set security level */ + if (p_data->sdp_ok.scn) + { + BTM_SetSecurityLevel (TRUE, "BTA_OPC", BTM_SEC_SERVICE_OBEX, + p_cb->sec_mask, BT_PSM_RFCOMM, + BTM_SEC_PROTO_RFCOMM, p_data->sdp_ok.scn); + srm = 0; + } + else + { + BTM_SetSecurityLevel (TRUE, "BTA_OPC", BTM_SEC_SERVICE_OBEX, + p_cb->sec_mask, p_data->sdp_ok.psm, 0, 0); + } + + if (status == OBX_SUCCESS) + { + OBX_CreateSession (p_cb->bd_addr, OBX_MAX_MTU, srm, 0, + p_cb->obx_handle, p_obx->p_pkt); + p_obx->p_pkt = NULL; /* OBX will free the memory */ + return; + } + } + else + { + p_data->obx_evt.rsp_code = OBX_RSP_FAILED; + bta_opc_sm_execute(p_cb, BTA_OPC_CLOSE_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_opc_free_db +** +** Description Free buffer used for service discovery database. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_free_db(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + utl_freebuf((void**)&p_cb->p_db); + p_cb->sdp_pending = FALSE; +} + +/******************************************************************************* +** +** Function bta_opc_ignore_obx +** +** Description Free OBX packet for ignored OBX events. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_ignore_obx(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + utl_freebuf((void**)&p_data->obx_evt.p_pkt); +} + +/******************************************************************************* +** +** Function bta_opc_find_service +** +** Description Perform service discovery to find the OPP service on the +** peer device. +** +** Returns void +** +*******************************************************************************/ +void bta_opc_find_service(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tSDP_UUID uuid_list; + UINT16 attr_list[3]; + + if (!p_cb->to_do) + return; + + bdcpy(p_cb->bd_addr, p_data->api_push.bd_addr); + if ((p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_OPC_DISC_SIZE)) != NULL) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + attr_list[2] = ATTR_ID_OBX_OVR_L2CAP_PSM; + + uuid_list.len = LEN_UUID_16; + uuid_list.uu.uuid16 = UUID_SERVCLASS_OBEX_OBJECT_PUSH; + p_cb->sdp_pending = TRUE; + SDP_InitDiscoveryDb(p_cb->p_db, BTA_OPC_DISC_SIZE, 1, &uuid_list, 3, attr_list); + if(!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, bta_opc_sdp_cback)) + { + bta_opc_sm_execute(p_cb, BTA_OPC_SDP_FAIL_EVT, (tBTA_OPC_DATA *)NULL); + } + } + else + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *)NULL); +} + +/******************************************************************************* +** +** Function bta_opc_close_complete +** +** Description Finishes the memory cleanup after a channel is closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_close_complete(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + p_cb->cout_active = FALSE; + bta_opc_initialize(p_cb, p_data); + + /* inform role manager */ + bta_sys_conn_close( BTA_ID_OPC ,p_cb->app_id, bta_opc_cb.bd_addr); + + p_cb->p_cback(BTA_OPC_CLOSE_EVT, (tBTA_OPC *)&p_cb->status); +} + +/******************************************************************************* +** +** Function bta_opc_set_disable +** +** Description Sets flag to disable. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_set_disable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + p_cb->disabling = TRUE; +} + +/******************************************************************************* +** +** Function bta_opc_chk_close +** +** Description Check if we need to stop the client now. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_chk_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + if (p_cb->single_op) + { + bta_opc_sm_execute(p_cb, BTA_OPC_API_CLOSE_EVT, (tBTA_OPC_DATA *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_opc_do_pull +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_do_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + APPL_TRACE_DEBUG1("bta_opc_do_pull to_do 0x%02x",p_cb->to_do); + bta_opc_send_get_req(p_cb); +} + +/******************************************************************************* +** +** Function bta_opc_do_push +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_do_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + APPL_TRACE_DEBUG1("bta_opc_do_push to_do 0x%02x",p_cb->to_do); + bta_opc_start_push(p_cb); +} + +/***************************************************************************** +** Callback Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_opc_obx_cback +** +** Description OBX callback function. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, UINT8 rsp_code, + tOBX_EVT_PARAM param, BT_HDR *p_pkt) +{ + tBTA_OPC_OBX_EVT *p_obx_msg; + UINT16 event = 0; + +#if BTA_OPC_DEBUG == TRUE + APPL_TRACE_DEBUG1("OBX Event Callback: obx_event [%s]", opc_obx_evt_code(obx_event)); +#endif + + switch(obx_event) + { + case OBX_CONNECT_RSP_EVT: + if (rsp_code == OBX_RSP_OK) + { + event = BTA_OPC_OBX_CONN_RSP_EVT; + } + else /* Obex will disconnect underneath BTA */ + { + APPL_TRACE_WARNING1("OPC_CBACK: Bad connect response 0x%02x", rsp_code); + if (p_pkt) + GKI_freebuf(p_pkt); + return; + } + break; + case OBX_PUT_RSP_EVT: + event = BTA_OPC_OBX_PUT_RSP_EVT; + break; + case OBX_GET_RSP_EVT: + event = BTA_OPC_OBX_GET_RSP_EVT; + break; + case OBX_CLOSE_IND_EVT: + event = BTA_OPC_OBX_CLOSE_EVT; + break; + case OBX_PASSWORD_EVT: + event = BTA_OPC_OBX_PASSWORD_EVT; + break; + + default: +/* case OBX_ABORT_RSP_EVT: */ +/* 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_OPC_OBX_EVT *) GKI_getbuf(sizeof(tBTA_OPC_OBX_EVT))) != NULL) + { + 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; + + bta_sys_sendmsg(p_obx_msg); + } +} + +/****************************************************************************** +** +** Function bta_opc_sdp_cback +** +** Description This is the SDP callback function used by OPC. +** 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_opc_sdp_cback(UINT16 status) +{ + tBTA_OPC_SDP_OK_EVT *p_buf; + tSDP_DISC_REC *p_rec = NULL; + tSDP_PROTOCOL_ELEM pe; + UINT8 scn = 0; + BOOLEAN found = FALSE; + UINT16 version = GOEP_LEGACY_VERSION; + UINT16 psm = 0; + tSDP_DISC_ATTR *p_attr; + + APPL_TRACE_DEBUG1("bta_opc_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(bta_opc_cb.p_db, + UUID_SERVCLASS_OBEX_OBJECT_PUSH, p_rec)) == NULL) + break; + + /* this is an optional attribute */ + SDP_FindProfileVersionInRec (p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH, &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; + 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 = GOEP_ENHANCED_VERSION; + } + break; + } + } + + /* If no OBEX over L2CAP look for RFCOMM SCN */ + if (!found) + { + /* get scn from proto desc list; if not found, go to next record */ + if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) + { + scn = (UINT8) pe.params[0]; + + /* we've got everything, we're done */ + found = TRUE; + break; + } + else + { + continue; + } + } + } while (TRUE); + } + + /* send result in event back to BTA */ + if ((p_buf = (tBTA_OPC_SDP_OK_EVT *) GKI_getbuf(sizeof(tBTA_OPC_SDP_OK_EVT))) != NULL) + { + if ((status == SDP_SUCCESS) && (found == TRUE)) + { + p_buf->hdr.event = BTA_OPC_SDP_OK_EVT; + p_buf->scn = scn; + p_buf->psm = psm; + p_buf->version = version; + } + else + p_buf->hdr.event = BTA_OPC_SDP_FAIL_EVT; + + bta_sys_sendmsg(p_buf); + } +} + +/***************************************************************************** +** Local OPP Event Processing Functions +*****************************************************************************/ + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_OPC_DEBUG == TRUE + +/******************************************************************************* +** +** Function opc_obx_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *opc_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"; + default: + return "unknown OBX event code"; + } +} +#endif /* Debug Functions */ diff --git a/bta/op/bta_opc_api.c b/bta/op/bta_opc_api.c new file mode 100644 index 0000000..4440b1c --- /dev/null +++ b/bta/op/bta_opc_api.c @@ -0,0 +1,214 @@ +/***************************************************************************** +** +** Name: bta_opc_api.c +** +** Description: This is the implementation of the API for the object +** push client 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 <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bta_fs_api.h" +#include "bta_op_api.h" +#include "bta_opc_int.h" +#include "bd.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_opc_reg = +{ + bta_opc_hdl_event, + BTA_OpcDisable +}; + +/******************************************************************************* +** +** Function BTA_OpcEnable +** +** Description Enable the object push client. This function must be +** called before any other functions in the DG API are called. +** When the enable operation is complete the callback function +** will be called with a BTA_OPC_ENABLE_EVT. +** +** If single_op is FALSE, the connection stays open after +** the operation finishes (until BTA_OpcClose is called). +** +** Returns void +** +*******************************************************************************/ +void BTA_OpcEnable(tBTA_SEC sec_mask, tBTA_OPC_CBACK *p_cback, + BOOLEAN single_op, BOOLEAN srm, UINT8 app_id) +{ + tBTA_OPC_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_OPC, &bta_opc_reg); + GKI_sched_unlock(); + + /* initialize control block */ + memset(&bta_opc_cb, 0, sizeof(tBTA_OPC_CB)); + + if ((p_buf = (tBTA_OPC_API_ENABLE *) GKI_getbuf(sizeof(tBTA_OPC_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_OPC_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->sec_mask = sec_mask; + p_buf->single_op = single_op; + p_buf->srm = srm; + p_buf->app_id = app_id; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_OpcDisable +** +** Description Disable the object push client. If the client is currently +** connected to a peer device the connection will be closed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_OpcDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_OPC); + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_OPC_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_OpcPush +** +** Description Push an object to a peer device. p_name must point to +** a fully qualified path and file name. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_OpcPush(BD_ADDR bd_addr, tBTA_OP_FMT format, char *p_name) +{ + tBTA_OPC_DATA *p_msg; + + if ((p_msg = (tBTA_OPC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_OPC_DATA) + + p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + p_msg->api_push.p_name = (char *)(p_msg + 1); + BCM_STRNCPY_S(p_msg->api_push.p_name, p_bta_fs_cfg->max_path_len+1, p_name, p_bta_fs_cfg->max_path_len); + p_msg->api_push.p_name[p_bta_fs_cfg->max_path_len] = '\0'; + p_msg->hdr.event = BTA_OPC_API_PUSH_EVT; + bdcpy(p_msg->api_push.bd_addr, bd_addr); + p_msg->api_push.format = format; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_OpcPullCard +** +** Description Pull default card from peer. p_path must point to a fully +** qualified path specifying where to store the pulled card. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_OpcPullCard(BD_ADDR bd_addr, char *p_path) +{ + tBTA_OPC_DATA *p_msg; + tBTA_OPC_API_PULL *p_pull; + + if ((p_msg = (tBTA_OPC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_OPC_DATA) + + (p_bta_fs_cfg->max_path_len + 1)))) != NULL) + { + p_pull = &p_msg->api_pull; + p_pull->p_path = (char *)(p_msg + 1); + BCM_STRNCPY_S(p_pull->p_path, p_bta_fs_cfg->max_path_len+1, p_path, p_bta_fs_cfg->max_path_len); + p_pull->p_path[p_bta_fs_cfg->max_path_len] = '\0'; + bdcpy(p_pull->bd_addr, bd_addr); + p_pull->hdr.event = BTA_OPC_API_PULL_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_OpcExchCard +** +** Description Exchange business cards with a peer device. p_send points to +** a fully qualified path and file name of vcard to push. +** p_recv_path points to a fully qualified path specifying +** where to store the pulled card. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_OpcExchCard(BD_ADDR bd_addr, char *p_send, char *p_recv_path) +{ + tBTA_OPC_DATA *p_msg; + tBTA_OPC_API_EXCH *p_exch; + + if(!p_send || !p_recv_path) + return; + + if ((p_msg = (tBTA_OPC_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_OPC_DATA) + + (p_bta_fs_cfg->max_path_len + 1) * 2))) != NULL) + { + p_exch = &p_msg->api_exch; + p_exch->p_send = (char *)(p_msg + 1); + p_exch->p_rcv_path = (char *)(p_exch->p_send + p_bta_fs_cfg->max_path_len + 1); + BCM_STRNCPY_S(p_exch->p_send, p_bta_fs_cfg->max_path_len+1, p_send, p_bta_fs_cfg->max_path_len); + p_exch->p_send[p_bta_fs_cfg->max_path_len] = '\0'; + BCM_STRNCPY_S(p_exch->p_rcv_path, p_bta_fs_cfg->max_path_len+1, p_recv_path, p_bta_fs_cfg->max_path_len); + p_exch->p_rcv_path[p_bta_fs_cfg->max_path_len] = '\0'; + bdcpy(p_exch->bd_addr, bd_addr); + p_exch->hdr.event = BTA_OPC_API_EXCH_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_OpcClose +** +** Description Close the current connection. This function is called if +** the phone wishes to close the connection before the object +** push is completed. In a typical connection this function +** does not need to be called; the connection will be closed +** automatically when the object push is complete. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_OpcClose(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_OPC_API_CLOSE_EVT; + bta_sys_sendmsg(p_buf); + } +} + + diff --git a/bta/op/bta_opc_int.h b/bta/op/bta_opc_int.h new file mode 100644 index 0000000..e26d2b5 --- /dev/null +++ b/bta/op/bta_opc_int.h @@ -0,0 +1,257 @@ +/***************************************************************************** +** +** Name: bta_opc_int.h +** +** Description: This is the private header file for the Object Push +** Client (OPC). +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_OPC_INT_H +#define BTA_OPC_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_op_api.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + + +#define OPC_DEF_NAME "default_opc.vcf" + +/* if the pulled vCard does not have a Name Header associated with it, + * this is the default name used to received the file. + * Please make sure that this is of different file name than the local + * default vCard file name */ +#ifndef OPC_DEF_RCV_NAME +#define OPC_DEF_RCV_NAME "opc_def_rcv.vcf" +#endif + +/* OPC Active opp obex operation (Valid in connected state) */ +#define OPC_OP_NONE 0 +#define OPC_OP_PULL_OBJ 1 +#define OPC_OP_PUSH_OBJ 2 + +/* Constants used for "to_do" list */ +#define BTA_OPC_PUSH_MASK 0x01 +#define BTA_OPC_PULL_MASK 0x02 + +/* state machine events */ +enum +{ + /* these events are handled by the state machine */ + BTA_OPC_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_OPC), + BTA_OPC_API_DISABLE_EVT, + BTA_OPC_API_CLOSE_EVT, /* Close connection event */ + BTA_OPC_API_PUSH_EVT, /* Push Object request */ + BTA_OPC_API_PULL_EVT, /* Pull Object request */ + BTA_OPC_API_EXCH_EVT, /* Exchange business Cards */ + BTA_OPC_SDP_OK_EVT, /* Service search was successful */ + BTA_OPC_SDP_FAIL_EVT, /* Service search failed */ + BTA_OPC_CI_WRITE_EVT, /* Call-in response to Write request */ + BTA_OPC_CI_READ_EVT, /* Call-in response to Read request */ + BTA_OPC_CI_OPEN_EVT, /* Call-in response to File Open request */ + BTA_OPC_OBX_CONN_RSP_EVT, /* OBX Channel Connect Request */ + BTA_OPC_OBX_PASSWORD_EVT, /* OBX password requested */ + BTA_OPC_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */ + BTA_OPC_OBX_PUT_RSP_EVT, /* Write file data or delete */ + BTA_OPC_OBX_GET_RSP_EVT, /* Read file data or folder listing */ + BTA_OPC_OBX_CMPL_EVT, /* operation has completed */ + BTA_OPC_CLOSE_CMPL_EVT, /* Finish the closing of the channel */ + BTA_OPC_DISABLE_CMPL_EVT /* Transition to disabled state */ +}; + +typedef UINT16 tBTA_OPC_INT_EVT; + +typedef UINT8 tBTA_OPC_STATE; + +/* data type for BTA_OPC_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_OPC_CBACK *p_cback; + UINT8 sec_mask; + BOOLEAN single_op; + BOOLEAN srm; + UINT8 app_id; +} tBTA_OPC_API_ENABLE; + +/* data type for BTA_OPC_API_PUSH_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + char *p_name; + tBTA_OP_FMT format; +} tBTA_OPC_API_PUSH; + +/* data type for BTA_OPC_API_PULL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + char *p_path; +} tBTA_OPC_API_PULL; + +/* data type for BTA_OPC_API_EXCH_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + char *p_send; + char *p_rcv_path; +} tBTA_OPC_API_EXCH; + +/* data type for BTA_OPC_SDP_OK_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 scn; + UINT16 psm; + UINT16 version; +} tBTA_OPC_SDP_OK_EVT; + +/* data type for all obex events + hdr.event contains the OPC 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_OPC_OBX_EVT; + +/* union of all event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_OPC_API_ENABLE api_enable; + tBTA_OPC_API_PUSH api_push; + tBTA_OPC_API_PULL api_pull; + tBTA_OPC_API_EXCH api_exch; + tBTA_OPC_SDP_OK_EVT sdp_ok; + tBTA_OPC_OBX_EVT obx_evt; + tBTA_FS_CI_OPEN_EVT open_evt; + tBTA_FS_CI_READ_EVT read_evt; + tBTA_FS_CI_WRITE_EVT write_evt; +} tBTA_OPC_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 leop in Obx packet */ + BOOLEAN final_pkt; /* (Get) Holds the final bit of the Put packet */ + UINT8 rsp_code; +} tBTA_OPC_OBX_PKT; + +/* Power management state for OPC */ +#define BTA_OPC_PM_BUSY 0 +#define BTA_OPC_PM_IDLE 1 + +/* OPC control block */ +typedef struct +{ + tBTA_OPC_CBACK *p_cback; /* pointer to application callback function */ + char *p_name; /* Holds the local path and file name of pushed item */ + char *p_rcv_path; /* Holds the local path and file name of received item (card exch only) */ + tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */ + tBTA_OPC_OBX_PKT obx; /* Holds the current OBX packet information */ + int fd; /* File Descriptor of opened file */ + UINT32 obj_size; /* (Push/Pull) file length */ + tOBX_HANDLE obx_handle; + UINT16 peer_mtu; + BD_ADDR bd_addr; + BOOLEAN single_op; /* if TRUE, close OBX connection when OP finishes */ + UINT8 sec_mask; + tBTA_OPC_STATE state; /* state machine state */ + tBTA_OP_FMT format; + UINT8 obx_oper; /* current active OBX operation PUT FILE or GET FILE */ + UINT8 to_do; /* actions to be done (push,pull) */ + UINT8 app_id; + tBTA_OPC_STATUS status; + tBTA_OPC_STATUS exch_status; + BOOLEAN first_get_pkt; /* TRUE if retrieving the first packet of GET object */ + BOOLEAN cout_active; /* TRUE if call-out is currently active */ + BOOLEAN req_pending; /* TRUE if an obx request to peer is in progress */ + BOOLEAN disabling; /* TRUE if an disabling client */ + BOOLEAN sdp_pending; /* TRUE when waiting for SDP to complete */ + BOOLEAN srm; /* TRUE, to use SIngle Response Mode */ + UINT8 pm_state; +} tBTA_OPC_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* OPC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_OPC_CB bta_opc_cb; +#else +extern tBTA_OPC_CB *bta_opc_cb_ptr; +#define bta_opc_cb (*bta_opc_cb_ptr) +#endif + + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +extern BOOLEAN bta_opc_hdl_event(BT_HDR *p_msg); +extern void bta_opc_sm_execute(tBTA_OPC_CB *p_cb, UINT16 event, + tBTA_OPC_DATA *p_data); +extern void bta_opc_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event, + UINT8 rsp_code, tOBX_EVT_PARAM param, + BT_HDR *p_pkt); + +/* action functions */ +extern void bta_opc_init_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_init_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_init_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_init_exch(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_send_authrsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_ci_write(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_ci_read(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_ci_open(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_obx_conn_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_obx_put_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_obx_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_initialize(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_trans_cmpl(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_stop_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_start_client(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_free_db(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_ignore_obx(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_find_service(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_close_complete(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_set_disable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_chk_close(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_do_pull(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_do_push(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_enable(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); + +/* miscellaneous functions */ +extern UINT8 bta_opc_send_get_req(tBTA_OPC_CB *p_cb); +extern BOOLEAN bta_opc_proc_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); +extern void bta_opc_cont_get_rsp(tBTA_OPC_CB *p_cb); +extern UINT8 bta_opc_send_put_req(tBTA_OPC_CB *p_cb, BOOLEAN first_pkt); +extern void bta_opc_start_push(tBTA_OPC_CB *p_cb); +extern void bta_opc_listing_err(BT_HDR **p_pkt, tBTA_OPC_STATUS status); + +extern tBTA_OPC_STATUS bta_opc_convert_obx_to_opc_status(tOBX_STATUS obx_status); + +#endif /* BTA_OPC_INT_H */ diff --git a/bta/op/bta_opc_main.c b/bta/op/bta_opc_main.c new file mode 100644 index 0000000..cf76143 --- /dev/null +++ b/bta/op/bta_opc_main.c @@ -0,0 +1,425 @@ +/***************************************************************************** +** +** Name: bta_opc_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 "bta_opc_int.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* state machine states */ +enum +{ + BTA_OPC_DISABLED_ST = 0, /* Disabled */ + BTA_OPC_IDLE_ST, /* Idle */ + BTA_OPC_W4_CONN_ST, /* Waiting for an Obex connect response */ + BTA_OPC_CONN_ST, /* Connected - OPP Session is active */ + BTA_OPC_CLOSING_ST /* Closing is in progress */ +}; + +/* state machine action enumeration list */ +enum +{ + BTA_OPC_START_CLIENT, + BTA_OPC_STOP_CLIENT, + BTA_OPC_INIT_PULL, + BTA_OPC_INIT_PUSH, + BTA_OPC_INIT_EXCH, + BTA_OPC_CI_WRITE, + BTA_OPC_CI_READ, + BTA_OPC_CI_OPEN, + BTA_OPC_OBX_CONN_RSP, + BTA_OPC_CLOSE, + BTA_OPC_OBX_PUT_RSP, + BTA_OPC_OBX_GET_RSP, + BTA_OPC_TRANS_CMPL, + BTA_OPC_FREE_DB, + BTA_OPC_IGNORE_OBX, + BTA_OPC_FIND_SERVICE, + BTA_OPC_INITIALIZE, + BTA_OPC_CLOSE_COMPLETE, + BTA_OPC_SET_DISABLE, + BTA_OPC_CHK_CLOSE, + BTA_OPC_DO_PUSH, + BTA_OPC_DO_PULL, + BTA_OPC_ENABLE, + BTA_OPC_IGNORE +}; + +/* type for action functions */ +typedef void (*tBTA_OPC_ACTION)(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data); + +/* action function list */ +const tBTA_OPC_ACTION bta_opc_action[] = +{ + bta_opc_start_client, + bta_opc_stop_client, + bta_opc_init_pull, + bta_opc_init_push, + bta_opc_init_exch, + bta_opc_ci_write, + bta_opc_ci_read, + bta_opc_ci_open, + bta_opc_obx_conn_rsp, + bta_opc_close, + bta_opc_obx_put_rsp, + bta_opc_obx_get_rsp, + bta_opc_trans_cmpl, + bta_opc_free_db, + bta_opc_ignore_obx, + bta_opc_find_service, + bta_opc_initialize, + bta_opc_close_complete, + bta_opc_set_disable, + bta_opc_chk_close, + bta_opc_do_push, + bta_opc_do_pull, + bta_opc_enable +}; + + +/* state table information */ +#define BTA_OPC_ACTIONS 2 /* number of actions */ +#define BTA_OPC_NEXT_STATE 2 /* position of next state */ +#define BTA_OPC_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for disabled state (enable is handled*/ +static const UINT8 bta_opc_st_disabled[][BTA_OPC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_ENABLE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}, +/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}, +/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}, +/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}, +/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}, +/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST} +}; + +/* state table for idle state */ +static const UINT8 bta_opc_st_idle[][BTA_OPC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_INITIALIZE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST}, +/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_INIT_PUSH, BTA_OPC_FIND_SERVICE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_INIT_PULL, BTA_OPC_FIND_SERVICE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_INIT_EXCH, BTA_OPC_FIND_SERVICE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST} +}; + +/* state table for wait for authentication response state */ +static const UINT8 bta_opc_st_w4_conn[][BTA_OPC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_SET_DISABLE, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_STOP_CLIENT, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_START_CLIENT, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_CLOSE_COMPLETE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_OBX_CONN_RSP, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_STOP_CLIENT, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_W4_CONN_ST}, +/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_TRANS_CMPL, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST} +}; + +/* state table for open state */ +static const UINT8 bta_opc_st_connected[][BTA_OPC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_SET_DISABLE, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_STOP_CLIENT, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_INIT_PUSH, BTA_OPC_DO_PUSH, BTA_OPC_CONN_ST}, +/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_INIT_PULL, BTA_OPC_DO_PULL, BTA_OPC_CONN_ST}, +/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_INIT_EXCH, BTA_OPC_DO_PUSH, BTA_OPC_CONN_ST}, +/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_CI_WRITE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_CI_READ, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_CI_OPEN, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_OBX_PUT_RSP, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_OBX_GET_RSP, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_TRANS_CMPL, BTA_OPC_CHK_CLOSE, BTA_OPC_CONN_ST}, +/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CONN_ST}, +/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST} +}; + +/* state table for closing state */ +static const UINT8 bta_opc_st_closing[][BTA_OPC_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* BTA_OPC_API_ENABLE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_DISABLE_EVT */ {BTA_OPC_SET_DISABLE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_CLOSE_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_PUSH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_PULL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_API_EXCH_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_SDP_OK_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_SDP_FAIL_EVT */ {BTA_OPC_FREE_DB, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_CI_WRITE_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CI_READ_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_CI_OPEN_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_OBX_CONN_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_STOP_CLIENT, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_PASSWORD_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_CLOSE_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_CLOSE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_PUT_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_GET_RSP_EVT */ {BTA_OPC_IGNORE_OBX, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_OBX_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_CLOSING_ST}, +/* BTA_OPC_CLOSE_CMPL_EVT */ {BTA_OPC_CLOSE_COMPLETE,BTA_OPC_IGNORE, BTA_OPC_IDLE_ST}, +/* BTA_OPC_DISABLE_CMPL_EVT */ {BTA_OPC_IGNORE, BTA_OPC_IGNORE, BTA_OPC_DISABLED_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_OPC_ST_TBL)[BTA_OPC_NUM_COLS]; + +/* state table */ +const tBTA_OPC_ST_TBL bta_opc_st_tbl[] = +{ + bta_opc_st_disabled, + bta_opc_st_idle, + bta_opc_st_w4_conn, + bta_opc_st_connected, + bta_opc_st_closing +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* OPC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_OPC_CB bta_opc_cb; +#endif + +#if BTA_OPC_DEBUG == TRUE +static char *opc_evt_code(tBTA_OPC_INT_EVT evt_code); +static char *opc_state_code(tBTA_OPC_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_opc_sm_execute +** +** Description State machine event handling function for OPC +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_sm_execute(tBTA_OPC_CB *p_cb, UINT16 event, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_ST_TBL state_table; + UINT8 action; + int i; + + /* look up the state table for the current state */ + state_table = bta_opc_st_tbl[p_cb->state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->state = state_table[event][BTA_OPC_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_OPC_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_OPC_IGNORE) + { + (*bta_opc_action[action])(p_cb, p_data); + } + else + { + break; + } + } +} + +/******************************************************************************* +** +** Function bta_opc_hdl_event +** +** Description File transfer server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_opc_hdl_event(BT_HDR *p_msg) +{ + tBTA_OPC_CB *p_cb = &bta_opc_cb; + +#if BTA_OPC_DEBUG == TRUE + tBTA_OPC_STATE in_state = p_cb->state; + APPL_TRACE_DEBUG3("OPC Event Handler: State 0x%02x [%s], Event [%s]", in_state, + opc_state_code(in_state), + opc_evt_code(p_msg->event)); +#endif + + bta_opc_sm_execute(p_cb, p_msg->event, (tBTA_OPC_DATA *) p_msg); + + if ( p_cb->state == BTA_OPC_CONN_ST ) + { + if (( p_cb->pm_state == BTA_OPC_PM_IDLE ) + &&( p_cb->obx_oper != OPC_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA OPC informs DM/PM busy state"); + bta_sys_busy( BTA_ID_OPC, p_cb->app_id, p_cb->bd_addr ); + p_cb->pm_state = BTA_OPC_PM_BUSY; + } + else if (( p_cb->pm_state == BTA_OPC_PM_BUSY ) + &&( p_cb->obx_oper == OPC_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA OPC informs DM/PM idle state"); + bta_sys_idle( BTA_ID_OPC ,p_cb->app_id, p_cb->bd_addr); + p_cb->pm_state = BTA_OPC_PM_IDLE; + } + } + else if ( p_cb->state == BTA_OPC_IDLE_ST ) + { + /* initialize power management state */ + p_cb->pm_state = BTA_OPC_PM_BUSY; + } + +#if BTA_OPC_DEBUG == TRUE + if (in_state != p_cb->state) + { + APPL_TRACE_DEBUG3("OPC State Change: [%s] -> [%s] after Event [%s]", + opc_state_code(in_state), + opc_state_code(p_cb->state), + opc_evt_code(p_msg->event)); + } +#endif + + return (TRUE); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_OPC_DEBUG == TRUE + +/******************************************************************************* +** +** Function opc_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *opc_evt_code(tBTA_OPC_INT_EVT evt_code) +{ + switch(evt_code) + { + case BTA_OPC_API_ENABLE_EVT: + return "BTA_OPC_API_ENABLE_EVT"; + case BTA_OPC_API_DISABLE_EVT: + return "BTA_OPC_API_DISABLE_EVT"; + case BTA_OPC_API_CLOSE_EVT: + return "BTA_OPC_API_CLOSE_EVT"; + case BTA_OPC_API_PUSH_EVT: + return "BTA_OPC_API_PUSH_EVT"; + case BTA_OPC_API_PULL_EVT: + return "BTA_OPC_API_PULL_EVT"; + case BTA_OPC_API_EXCH_EVT: + return "BTA_OPC_API_EXCH_EVT"; + case BTA_OPC_SDP_OK_EVT: + return "BTA_OPC_SDP_OK_EVT"; + case BTA_OPC_SDP_FAIL_EVT: + return "BTA_OPC_SDP_FAIL_EVT"; + case BTA_OPC_CI_WRITE_EVT: + return "BTA_OPC_CI_WRITE_EVT"; + case BTA_OPC_CI_READ_EVT: + return "BTA_OPC_CI_READ_EVT"; + case BTA_OPC_CI_OPEN_EVT: + return "BTA_OPC_CI_OPEN_EVT"; + case BTA_OPC_OBX_CONN_RSP_EVT: + return "BTA_OPC_OBX_CONN_RSP_EVT"; + case BTA_OPC_OBX_PASSWORD_EVT: + return "BTA_OPC_OBX_PASSWORD_EVT"; + case BTA_OPC_OBX_CLOSE_EVT: + return "BTA_OPC_OBX_CLOSE_EVT"; + case BTA_OPC_OBX_PUT_RSP_EVT: + return "BTA_OPC_OBX_PUT_RSP_EVT"; + case BTA_OPC_OBX_GET_RSP_EVT: + return "BTA_OPC_OBX_GET_RSP_EVT"; + case BTA_OPC_OBX_CMPL_EVT: + return "BTA_OPC_OBX_CMPL_EVT"; + case BTA_OPC_CLOSE_CMPL_EVT: + return "BTA_OPC_CLOSE_CMPL_EVT"; + case BTA_OPC_DISABLE_CMPL_EVT: + return "BTA_OPC_DISABLE_CMPL_EVT"; + default: + return "unknown OPC event code"; + } +} + +/******************************************************************************* +** +** Function opc_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *opc_state_code(tBTA_OPC_STATE state_code) +{ + switch(state_code) + { + case BTA_OPC_DISABLED_ST: + return "BTA_OPC_DISABLED_ST"; + case BTA_OPC_IDLE_ST: + return "BTA_OPC_IDLE_ST"; + case BTA_OPC_W4_CONN_ST: + return "BTA_OPC_W4_CONN_ST"; + case BTA_OPC_CONN_ST: + return "BTA_OPC_CONN_ST"; + case BTA_OPC_CLOSING_ST: + return "BTA_OPC_CLOSING_ST"; + default: + return "unknown OPC state code"; + } +} + +#endif /* Debug Functions */ diff --git a/bta/op/bta_opc_utils.c b/bta/op/bta_opc_utils.c new file mode 100644 index 0000000..82e626c --- /dev/null +++ b/bta/op/bta_opc_utils.c @@ -0,0 +1,322 @@ +/***************************************************************************** +** +** Name: bta_opc_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 <stdio.h> +#include <string.h> +#include "bta_opc_int.h" +#include "bta_fs_api.h" +#include "bta_fs_co.h" +#include "gki.h" +#include "utl.h" + +/******************************************************************************* +** Constants +*******************************************************************************/ + +/******************************************************************************* +** Local Function Prototypes +*******************************************************************************/ + +/******************************************************************************* +* Macros for OPC +*******************************************************************************/ + +/******************************************************************************* +* Exported Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function bta_opc_send_get_req +** +** Description Processes a Get File Operation. +** +** Parameters p_cb - Pointer to the OPC control block +** +** Returns (UINT8) OBX response code +** +*******************************************************************************/ +UINT8 bta_opc_send_get_req(tBTA_OPC_CB *p_cb) +{ + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + UINT8 rsp_code = OBX_RSP_FAILED; + + utl_freebuf((void**)&p_obx->p_pkt); + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, p_cb->peer_mtu)) != NULL) + { + /* If first request add the Type Header to the request */ + if (p_cb->first_get_pkt == TRUE) + { + p_cb->obx_oper = OPC_OP_PULL_OBJ; + p_cb->to_do &= ~BTA_OPC_PULL_MASK; + OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vcard"); + } + + if ((OBX_GetReq(p_cb->obx_handle, TRUE, p_obx->p_pkt)) == OBX_SUCCESS) + { + rsp_code = OBX_RSP_OK; + p_obx->p_pkt = NULL; + p_cb->req_pending = TRUE; + } + } + + return (rsp_code); +} + +/******************************************************************************* +** +** Function bta_opc_cont_get_rsp +** +** Description Continues an obex get response packet. +** This function is called upon completion of a file open or +** a file write event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_opc_cont_get_rsp(tBTA_OPC_CB *p_cb) +{ + tBTA_OPC_OBX_EVT obx_evt; + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + UINT16 body_size; + BOOLEAN end; + + /* Read the body header from the obx packet if it exists */ + if (OBX_ReadBodyHdr(p_obx->p_pkt, &p_obx->p_start, &body_size, &end)) + { + p_obx->final_pkt = end; + if (body_size) + { + /* Data to be written */ + 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_OPC_CI_WRITE_EVT, 0, p_cb->app_id); + return; + } + } + + /* Empty Body; send next request or finished */ + if (!p_obx->final_pkt) + { + bta_opc_send_get_req(p_cb); + } + else /* Done getting object */ + { + memset(&obx_evt, 0, sizeof(tBTA_OPC_OBX_EVT)); + obx_evt.rsp_code = OBX_RSP_OK; + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, (tBTA_OPC_DATA *) &obx_evt); + utl_freebuf((void**)&p_obx->p_pkt); + } +} + +/******************************************************************************* +** +** Function bta_opc_proc_get_rsp +** +** Description Processes an obex get response packet. +** Initiates a file open if no errors. +** +** +** Returns BOOLEAN - TRUE if obex packet is to be freed +** +*******************************************************************************/ +BOOLEAN bta_opc_proc_get_rsp(tBTA_OPC_CB *p_cb, tBTA_OPC_DATA *p_data) +{ + tBTA_OPC_OBX_EVT *p_evt = &p_data->obx_evt; + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + char *p_filename; + + if (p_evt->rsp_code == OBX_RSP_OK || p_evt->rsp_code == OBX_RSP_CONTINUE) + { + /* The get the file name */ + if (!OBX_ReadUtf8NameHdr(p_obx->p_pkt, (UINT8 *) p_cb->p_name, + p_bta_fs_cfg->max_file_len)) + BCM_STRNCPY_S(p_cb->p_name, p_bta_fs_cfg->max_path_len+1, OPC_DEF_RCV_NAME, sizeof(OPC_DEF_RCV_NAME)+1); + + /* If length header exists, save the file length */ + if (!OBX_ReadLengthHdr(p_obx->p_pkt, &p_cb->obj_size)) + p_cb->obj_size = BTA_FS_LEN_UNKNOWN; + + /* Build the file name with a fully qualified path */ + if ((p_filename = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + sprintf(p_filename, "%s%c%s", p_cb->p_rcv_path, + p_bta_fs_cfg->path_separator, + p_cb->p_name); + + p_cb->cout_active = TRUE; + bta_fs_co_open(p_filename, + (BTA_FS_O_RDWR | BTA_FS_O_CREAT | BTA_FS_O_TRUNC), + p_cb->obj_size, BTA_OPC_CI_OPEN_EVT, p_cb->app_id); + + GKI_freebuf(p_filename); + return FALSE; /* Do not free the obex packet until data is written */ + } + else + p_evt->rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + + /* Server returned an error or out of memory to process request */ + bta_opc_sm_execute(p_cb, BTA_OPC_OBX_CMPL_EVT, p_data); + + return TRUE; +} + +/******************************************************************************* +** +** Function bta_opc_send_put_req +** +** Description Initiates/Continues a Put Object 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_opc_send_put_req(tBTA_OPC_CB *p_cb, BOOLEAN first_pkt) +{ + tBTA_OPC_OBX_PKT *p_obx = &p_cb->obx; + UINT8 rsp_code = OBX_RSP_FAILED; + char *p_ch; + + utl_freebuf((void**)&p_obx->p_pkt); + if ((p_obx->p_pkt = OBX_HdrInit(p_cb->obx_handle, OBX_LRG_DATA_POOL_SIZE)) != NULL) + { + /* 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 == NULL) + p_ch = p_cb->p_name; + + 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->obj_size != BTA_FS_LEN_UNKNOWN) + { + OBX_AddLengthHdr(p_obx->p_pkt, p_cb->obj_size); + } + + /* Add the type header if known */ + switch (p_cb->format) + { + case BTA_OP_VCARD30_FMT: + case BTA_OP_VCARD21_FMT: + OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vcard"); + break; + case BTA_OP_VCAL_FMT: + case BTA_OP_ICAL_FMT: + OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vcalendar"); + break; + case BTA_OP_VNOTE_FMT: + OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vnote"); + break; + case BTA_OP_VMSG_FMT: + OBX_AddTypeHdr(p_obx->p_pkt, "text/x-vmessage"); + break; + } + + OBX_PutReq(p_cb->obx_handle, FALSE, p_obx->p_pkt); + p_obx->p_pkt = NULL; + p_cb->req_pending = TRUE; + rsp_code = OBX_RSP_OK; + } + else + APPL_TRACE_ERROR1("Invalid file name [%s] feed, PutReq NOT sent.", p_cb->p_name); + + } + else /* A continuation packet so read object data */ + { + /* 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); + + /* 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_OPC_CI_READ_EVT, 0, p_cb->app_id); + rsp_code = OBX_RSP_OK; + } + } + + return (rsp_code); +} + +/******************************************************************************* +** +** Function bta_opc_start_push +** +** Description Push an object to connected server. +** Opens the object to be transferred to the server. +** +** Returns void +** +*******************************************************************************/ +void bta_opc_start_push(tBTA_OPC_CB *p_cb) +{ + p_cb->to_do &= ~BTA_OPC_PUSH_MASK; + p_cb->obx_oper = OPC_OP_PUSH_OBJ; + p_cb->cout_active = TRUE; + + bta_fs_co_open(p_cb->p_name, BTA_FS_O_RDONLY, 0, BTA_OPC_CI_OPEN_EVT, + p_cb->app_id); +} + +/******************************************************************************* +** +** Function bta_opc_convert_obx_to_opc_status +** +** Description Convert OBX response code into BTA OPC status code. +** +** Returns void +** +*******************************************************************************/ +tBTA_OPC_STATUS bta_opc_convert_obx_to_opc_status(tOBX_STATUS obx_status) +{ + tBTA_OPC_STATUS status; + + switch (obx_status) + { + case OBX_RSP_OK: + case OBX_RSP_CONTINUE: + status = BTA_OPC_OK; + break; + case OBX_RSP_UNAUTHORIZED: + status = BTA_OPC_NO_PERMISSION; + break; + case OBX_RSP_NOT_FOUND: + status = BTA_OPC_NOT_FOUND; + break; + case OBX_RSP_SERVICE_UNAVL: + status = BTA_OPC_SRV_UNAVAIL; + break; + case OBX_RSP_FORBIDDEN: + status = BTA_OPC_RSP_FORBIDDEN; + break; + case OBX_RSP_NOT_ACCEPTABLE: + status = BTA_OPC_RSP_NOT_ACCEPTABLE; + break; + default: + status = BTA_OPC_FAIL; + } + + return (status); +} diff --git a/bta/op/bta_ops_act.c b/bta/op/bta_ops_act.c new file mode 100644 index 0000000..5409cf1 --- /dev/null +++ b/bta/op/bta_ops_act.c @@ -0,0 +1,793 @@ +/***************************************************************************** +** +** Name: bta_ops_act.c +** +** Description: This file contains the object 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_OP_INCLUDED) && (BTA_OP_INCLUDED) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_op_api.h" +#include "bta_ops_int.h" +#include "bta_fs_api.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#include "rfcdefs.h" /* BT_PSM_RFCOMM */ +#include "btm_api.h" +#include "utl.h" +#include "goep_util.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_OPS_NUM_FMTS 7 +#define BTA_OPS_PROTOCOL_COUNT 3 + +/* object format lookup table */ +const tBTA_OP_FMT bta_ops_obj_fmt[] = +{ + BTA_OP_VCARD21_FMT, + BTA_OP_VCARD30_FMT, + BTA_OP_VCAL_FMT, + BTA_OP_ICAL_FMT, + BTA_OP_VNOTE_FMT, + BTA_OP_VMSG_FMT, + BTA_OP_OTHER_FMT +}; + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +#if BTA_OPS_DEBUG == TRUE +static char *ops_obx_evt_code(tOBX_EVENT evt_code); +#endif + +/***************************************************************************** +** Action Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_ops_enable +** +** Description Perform necessary operations to enable object push. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_enable(tBTA_OPS_CB *p_cb, tBTA_OPS_API_ENABLE *p_data) +{ + tOBX_StartParams start_params; + UINT16 servclass = UUID_SERVCLASS_OBEX_OBJECT_PUSH; + int i, j; + tBTA_UTL_COD cod; + tOBX_STATUS status; + UINT8 desc_type[BTA_OPS_NUM_FMTS]; + UINT8 type_len[BTA_OPS_NUM_FMTS]; + UINT8 *type_value[BTA_OPS_NUM_FMTS]; + UINT16 mtu = OBX_MAX_MTU; + UINT8 temp[4], *p; + UINT16 version = GOEP_ENHANCED_VERSION; + + /* allocate scn for opp */ + p_cb->scn = BTM_AllocateSCN(); + p_cb->app_id = p_data->app_id; + + /* set security level */ + BTM_SetSecurityLevel (FALSE, (char *) "", BTM_SEC_SERVICE_OBEX, + p_data->sec_mask, BT_PSM_RFCOMM, + BTM_SEC_PROTO_RFCOMM, p_cb->scn); + + p_cb->psm = L2CA_AllocatePSM(); + BTM_SetSecurityLevel (FALSE, (char *) "", BTM_SEC_SERVICE_OBEX, + p_data->sec_mask, p_cb->psm, 0, 0); + + memset (&start_params, 0, sizeof(tOBX_StartParams)); + start_params.p_target = NULL; + start_params.p_cback = &bta_ops_obx_cback; + start_params.mtu = mtu; + start_params.scn = p_cb->scn; + start_params.psm = p_cb->psm; + start_params.srm = p_cb->srm; + start_params.nonce = 0; + start_params.authenticate = FALSE; + start_params.auth_option = OBX_AO_NONE; + start_params.realm_charset = OBX_RCS_ASCII; + start_params.p_realm = NULL; + start_params.realm_len = 0; + + if ((status = OBX_StartServer (&start_params, &p_cb->obx_handle)) == OBX_SUCCESS) + { + status = GOEP_Register (p_data->name, &p_cb->sdp_handle, p_cb->scn, 1, &servclass, + servclass, version); + + /* 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); + + /* add sequence for supported types */ + for (i = 0, j = 0; i < BTA_OPS_NUM_FMTS; i++) + { + if ((p_data->formats >> i) & 1) + { + type_value[j] = (UINT8 *) &bta_ops_obj_fmt[i]; + desc_type[j] = UINT_DESC_TYPE; + type_len[j++] = 1; + } + } + + SDP_AddSequence(p_cb->sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST, + (UINT8) j, desc_type, type_len, type_value); + + /* set class of device */ + cod.service = BTM_COD_SERVICE_OBJ_TRANSFER; + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); + + /* store formats value */ + p_cb->formats = p_data->formats; + } + bta_sys_add_uuid(servclass); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */ + + p_cb->p_cback(BTA_OPS_ENABLE_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_ops_api_disable +** +** Description Perform necessary operations to disable object push. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_api_disable(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + /* Free any outstanding headers and control block memory */ + bta_ops_clean_getput(p_cb, TRUE); + + /* Stop the OBEX server */ + OBX_StopServer(p_cb->obx_handle); + + /* Remove the OPP service from the SDP database */ + SDP_DeleteRecord(p_cb->sdp_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH); + + /* Free the allocated server channel number */ + BTM_FreeSCN(p_cb->scn); + BTM_SecClrService(BTM_SEC_SERVICE_OBEX); +} + +/******************************************************************************* +** +** Function bta_ops_api_accessrsp +** +** Description Process the access API event. +** If permission had been granted, continue the push or pull +** operation. +** +** Returns void +** +*******************************************************************************/ +void bta_ops_api_accessrsp(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + UINT8 rsp_code; + + /* Process the currently active access response */ + switch (p_cb->acc_active) + { + case BTA_OP_OPER_PUSH: + if (p_data->api_access.oper == BTA_OP_OPER_PUSH) + { + if (p_data->api_access.flag == BTA_OP_ACCESS_ALLOW) + { + /* Save the file name with path prepended */ + BCM_STRCPY_S(p_cb->p_path, p_bta_fs_cfg->max_path_len+1, p_data->api_access.p_name); + + APPL_TRACE_DEBUG2("OPS PUSH OBJ: Name [%s], Length = 0x%0x (0 = n/a)", + p_cb->p_path, p_cb->file_length); + + 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_OPS_CI_OPEN_EVT, + p_cb->app_id); + } + else /* Access denied or Unsupported */ + { + rsp_code = (p_data->api_access.flag == BTA_OP_ACCESS_NONSUP) + ? OBX_RSP_UNSUPTD_TYPE : OBX_RSP_UNAUTHORIZED; + bta_ops_clean_getput(p_cb, TRUE); + OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); + } + p_cb->acc_active = 0; + } + + break; + + case BTA_OP_OPER_PULL: + if (p_data->api_access.oper == BTA_OP_OPER_PULL) + { + if (p_data->api_access.flag == BTA_OP_ACCESS_ALLOW) + { + /* Save the file name with path prepended */ + BCM_STRCPY_S(p_cb->p_path, p_bta_fs_cfg->max_path_len+1, p_data->api_access.p_name); + + APPL_TRACE_DEBUG1("OPS PULL VCARD: Name [%s]", p_cb->p_path); + + p_cb->cout_active = TRUE; + bta_fs_co_open (p_cb->p_path, BTA_FS_O_RDONLY, 0, + BTA_OPS_CI_OPEN_EVT, p_cb->app_id); + } + else /* Denied */ + bta_ops_get_obj_rsp(OBX_RSP_UNAUTHORIZED, 0); + + p_cb->acc_active = 0; + } + break; + + default: + APPL_TRACE_WARNING1("OPS ACCRSP: Unknown tBTA_OP_OPER value (%d)", + p_cb->acc_active); + } +} + +/******************************************************************************* +** +** Function bta_ops_api_close +** +** Description Handle an api close event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_api_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + /* resources will be freed at BTA_OPS_OBX_CLOSE_EVT */ + OBX_DisconnectRsp(p_cb->obx_handle, OBX_RSP_SERVICE_UNAVL, NULL); +} + +/******************************************************************************* +** +** Function bta_ops_ci_write +** +** Description Continue with the current write operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_ci_write(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + UINT8 rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + p_cb->cout_active = FALSE; + + if (!p_cb->aborting) + { + /* Process write call-in event if operation is still active */ + if (p_cb->obx_oper == OPS_OP_PUSH_OBJ) + { + 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_ops_clean_getput(p_cb, TRUE); + } + + /* Process response to OBX client */ + bta_ops_put_obj_rsp(rsp_code); + } + } + else /* Finish aborting */ + { + bta_ops_clean_getput(p_cb, TRUE); + OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_ops_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_ops_ci_read(tBTA_OPS_CB *p_cb, tBTA_OPS_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->aborting) + { + /* Process read call-in event if operation is still active */ + if (p_cb->obx_oper == OPS_OP_PULL_OBJ && 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_ops_get_obj_rsp(rsp_code, p_revt->num_read); + } + } + else /* Finish aborting */ + { + bta_ops_clean_getput(p_cb, TRUE); + OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL); + APPL_TRACE_ERROR0("OPS PUSH OBJ: Finished ABORTING!!!"); + } +} + +/******************************************************************************* +** +** Function bta_ops_ci_open +** +** Description Continue with the current file open operation +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_ci_open(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_FS_CI_OPEN_EVT *p_open = &p_data->open_evt; + UINT8 rsp_code = OBX_RSP_OK; + UINT8 num_hdrs; + BOOLEAN endpkt; + char *p_name; + + p_cb->cout_active = FALSE; + + if (p_cb->aborting) + { + bta_ops_clean_getput(p_cb, TRUE); + OBX_AbortRsp(p_cb->obx_handle, OBX_RSP_OK, (BT_HDR *)NULL); + return; + } + + /* Only process file get or put operations */ + if (p_cb->obx_oper == OPS_OP_PULL_OBJ) + { + /* 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; + p_cb->file_length = p_open->file_size; + + /* Add the name and length headers */ + p_name = strrchr(p_cb->p_path, (int)p_bta_fs_cfg->path_separator); + if (p_name == NULL) + p_name = p_cb->p_path; + else + p_name++; /* increment past the file separator */ + + OBX_AddUtf8NameHdr(p_obx->p_pkt, (UINT8 *)p_name); + + 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; + } + } + + /* 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 */ + } + 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_ops_get_obj_rsp(rsp_code, 0); + } + } + else if (p_cb->obx_oper == OPS_OP_PUSH_OBJ) + { + /* 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_OPS_CI_WRITE_EVT, + 0, p_cb->app_id); + } + else if (num_hdrs > 1) /* Too many body headers to handle */ + { + rsp_code = OBX_RSP_BAD_REQUEST; + bta_ops_clean_getput(p_cb, TRUE); + } + else /* No body: respond with an OK so client can start sending the data */ + p_obx->bytes_left = 0; + } + 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 or no body */ + if (rsp_code != OBX_RSP_PART_CONTENT) + bta_ops_put_obj_rsp(rsp_code); + } +} + +/******************************************************************************* +** +** Function bta_ops_obx_connect +** +** Description Process the OBX connect event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_connect(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt; + + 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_EVENT1("OPS Connect: peer mtu 0x%04x", p_cb->peer_mtu); + + /* done with obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); + + OBX_ConnectRsp(p_evt->handle, OBX_RSP_OK, (BT_HDR *)NULL); + + /* inform role manager */ + bta_sys_conn_open( BTA_ID_OPS ,p_cb->app_id, bta_ops_cb.bd_addr); + + /* Notify the MMI that a connection has been opened */ + p_cb->p_cback(BTA_OPS_OPEN_EVT, (tBTA_OPS*)bta_ops_cb.bd_addr); +} + +/******************************************************************************* +** +** Function bta_ops_obx_disc +** +** Description Process the OBX disconnect event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_disc(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_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; + + /* Action operation is not supported in OPP, send reject rsp and free data */ + if(p_evt->obx_event == OBX_ACTION_REQ_EVT) + { + OBX_ActionRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + } + + OBX_DisconnectRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + + /* Done with Obex packet */ + utl_freebuf((void**)&p_evt->p_pkt); +} + +/******************************************************************************* +** +** Function bta_ops_obx_close +** +** Description Process the OBX link lost event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + /* finished if not waiting on a call-in function */ + if (!p_cb->cout_active) + bta_ops_sm_execute(p_cb, BTA_OPS_CLOSE_CMPL_EVT, p_data); +} + +/******************************************************************************* +** +** Function bta_ops_obx_abort +** +** Description Process the OBX abort event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_abort(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_OK; + + utl_freebuf((void**)&p_evt->p_pkt); + + if (!p_cb->cout_active) + { + bta_ops_clean_getput(p_cb, TRUE); + OBX_AbortRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); + } + else /* Delay the response if a call-out function is active */ + p_cb->aborting = TRUE; +} + +/******************************************************************************* +** +** Function bta_ops_obx_put +** +** Description Process the OBX push object put event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_put(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_CONTINUE; + + p_cb->obx.final_pkt = p_evt->param.put.final; + + /* If currently processing a push, use the current name */ + if (bta_ops_cb.obx_oper == OPS_OP_PUSH_OBJ) + { + bta_ops_proc_put_obj(p_evt->p_pkt); + } + + /* This is a new request; allocate enough memory to hold the path (including file name) */ + else if ((p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + + p_bta_fs_cfg->max_file_len + 2))) != NULL) + { + p_cb->p_name = (p_cb->p_path + p_bta_fs_cfg->max_path_len + 1); + p_cb->p_name[p_bta_fs_cfg->max_file_len] = '\0'; + p_cb->p_path[p_bta_fs_cfg->max_path_len] = '\0'; + + /* read the name header if it exists */ + if (OBX_ReadUtf8NameHdr(p_evt->p_pkt, (UINT8 *)p_cb->p_name, p_bta_fs_cfg->max_file_len)) + { + /* get file type from file name; check if supported */ + if ((p_cb->obj_fmt = bta_ops_fmt_supported(p_cb->p_name, + p_cb->formats)) != 0) + { + if(!(OBX_ReadLengthHdr(p_evt->p_pkt, &p_cb->file_length))) + p_cb->file_length = BTA_FS_LEN_UNKNOWN; + + p_cb->obx.p_pkt = p_evt->p_pkt; /* save the packet for later use */ + p_cb->obx.offset = 0; /* Initial offset into OBX data */ + p_cb->obx_oper = OPS_OP_PUSH_OBJ; + + /* request access from the app */ + bta_ops_req_app_access (BTA_OP_OPER_PUSH, p_cb); + } + else + rsp_code = OBX_RSP_UNSUPTD_TYPE; + } + else + rsp_code = OBX_RSP_BAD_REQUEST; + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + + /* Error has been detected; respond with error code */ + if (rsp_code != OBX_RSP_CONTINUE) + { + utl_freebuf((void**)&p_evt->p_pkt); /* done with obex packet */ + utl_freebuf((void**)&p_cb->p_path); + p_cb->p_name = NULL; + OBX_PutRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_ops_obx_get +** +** Description Process the OBX pull vCard object. +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_get(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + /* this is a new request; validate it */ + if (bta_ops_cb.obx_oper != OPS_OP_PULL_OBJ) + bta_ops_init_get_obj(p_cb, p_data); + else /* this is a continuation request */ + bta_ops_proc_get_obj(p_cb); + + /* done with Obex packet */ + utl_freebuf((void**)&p_data->obx_evt.p_pkt); +} + +/******************************************************************************* +** +** Function bta_ops_close_complete +** +** Description Finishes the memory cleanup after a channel is closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_close_complete(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + + /* inform role manager */ + bta_sys_conn_close( BTA_ID_OPS ,p_cb->app_id, bta_ops_cb.bd_addr); + + p_cb->cout_active = FALSE; + + bta_ops_clean_getput(p_cb, TRUE); + + /* Notify the MMI that a connection has been closed */ + p_cb->p_cback(BTA_OPS_CLOSE_EVT, (tBTA_OPS*)p_cb->bd_addr); + memset(p_cb->bd_addr, 0, BD_ADDR_LEN); + + if (p_data->obx_evt.p_pkt) + APPL_TRACE_WARNING0("OPS: OBX CLOSE CALLED WITH non-NULL Packet!!!"); +} + +/***************************************************************************** +** Callback Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_ops_obx_cback +** +** Description OBX callback function. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_obx_cback (tOBX_HANDLE handle, tOBX_EVENT obx_event, + tOBX_EVT_PARAM param, BT_HDR *p_pkt) +{ + tBTA_OPS_OBX_EVENT *p_obx_msg; + UINT16 event = 0; + +#if BTA_OPS_DEBUG == TRUE + APPL_TRACE_DEBUG1("OBX Event Callback: ops_obx_event[%s]", ops_obx_evt_code(obx_event)); +#endif + + switch(obx_event) + { + case OBX_CONNECT_REQ_EVT: + event = BTA_OPS_OBX_CONN_EVT; + break; + case OBX_DISCONNECT_REQ_EVT: + event = BTA_OPS_OBX_DISC_EVT; + break; + case OBX_PUT_REQ_EVT: + event = BTA_OPS_OBX_PUT_EVT; + break; + case OBX_GET_REQ_EVT: + event = BTA_OPS_OBX_GET_EVT; + break; + case OBX_ABORT_REQ_EVT: + event = BTA_OPS_OBX_ABORT_EVT; + break; + case OBX_CLOSE_IND_EVT: + event = BTA_OPS_OBX_CLOSE_EVT; + break; + case OBX_TIMEOUT_EVT: + break; + default: + /* Unrecognized packet; disconnect the session */ + if (p_pkt) + event = BTA_OPS_OBX_DISC_EVT; + } + + /* send event to BTA, if any */ + if (event && (p_obx_msg = + (tBTA_OPS_OBX_EVENT *) GKI_getbuf(sizeof(tBTA_OPS_OBX_EVENT))) != 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; + + bta_sys_sendmsg(p_obx_msg); + } +} + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_OPS_DEBUG == TRUE + +/******************************************************************************* +** +** Function ops_obx_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *ops_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"; + default: + return "unknown OBX event code"; + } +} +#endif /* Debug Functions */ +#endif /* BTA_OP_INCLUDED */ diff --git a/bta/op/bta_ops_api.c b/bta/op/bta_ops_api.c new file mode 100644 index 0000000..1c09094 --- /dev/null +++ b/bta/op/bta_ops_api.c @@ -0,0 +1,153 @@ +/***************************************************************************** +** +** Name: bta_ops_api.c +** +** Description: This is the implementation of the API for the object +** push 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_OP_INCLUDED) && (BTA_OP_INCLUDED) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bta_fs_api.h" +#include "bta_op_api.h" +#include "bta_ops_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_ops_reg = +{ + bta_ops_hdl_event, + BTA_OpsDisable +}; + +/******************************************************************************* +** +** Function BTA_OpsEnable +** +** Description Enable the object push server. This function must be +** called before any other functions in the OPS API are called. +** +** Returns void +** +*******************************************************************************/ +void BTA_OpsEnable(tBTA_SEC sec_mask, tBTA_OP_FMT_MASK formats, + char *p_service_name, tBTA_OPS_CBACK *p_cback, BOOLEAN srm, UINT8 app_id) +{ + tBTA_OPS_API_ENABLE *p_buf; + + GKI_sched_lock(); + /* register with BTA system manager */ + bta_sys_register(BTA_ID_OPS, &bta_ops_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_OPS_API_ENABLE *) GKI_getbuf(sizeof(tBTA_OPS_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_OPS_API_ENABLE_EVT; + BCM_STRNCPY_S(p_buf->name, sizeof(p_buf->name), p_service_name, BTA_SERVICE_NAME_LEN); + p_buf->name[BTA_SERVICE_NAME_LEN] = '\0'; + p_buf->p_cback = p_cback; + p_buf->app_id = app_id; + p_buf->formats = formats; + p_buf->sec_mask = sec_mask; + p_buf->srm = srm; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_OpsDisable +** +** Description Disable the object push server. If the server is currently +** connected to a peer device the connection will be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_OpsDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_OPS); + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_OPS_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_OpsClose +** +** Description Close the current connection. This function is called if +** the phone wishes to close the connection before the object +** push is completed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_OpsClose(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_OPS_API_CLOSE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_OpsAccessRsp +** +** Description Sends a reply to an access request event (BTA_OPS_ACCESS_EVT). +** This call MUST be made whenever the event occurs. +** +** Parameters oper - operation being accessed. +** access - BTA_OP_ACCESS_ALLOW, BTA_OP_ACCESS_FORBID, or +** BTA_OP_ACCESS_NONSUP. +** p_name - Full path of file to read from (pull) or write to +** (push). +** +** Returns void +** +*******************************************************************************/ +void BTA_OpsAccessRsp(tBTA_OP_OPER oper, tBTA_OP_ACCESS access, char *p_name) +{ + tBTA_OPS_API_ACCESSRSP *p_buf; + + if ((p_buf = (tBTA_OPS_API_ACCESSRSP *)GKI_getbuf((UINT16)(sizeof(tBTA_OPS_API_ACCESSRSP) + + p_bta_fs_cfg->max_path_len + 1))) != NULL) + { + p_buf->flag = access; + p_buf->oper = oper; + p_buf->p_name = (char *)(p_buf + 1); + if (p_name) + { + BCM_STRNCPY_S(p_buf->p_name, p_bta_fs_cfg->max_path_len+1, p_name, p_bta_fs_cfg->max_path_len); + p_buf->p_name[p_bta_fs_cfg->max_path_len] = '\0'; + } + else + *p_buf->p_name = '\0'; + + p_buf->hdr.event = BTA_OPS_API_ACCESSRSP_EVT; + bta_sys_sendmsg(p_buf); + } +} +#endif /* BTA_OP_INCLUDED */ diff --git a/bta/op/bta_ops_int.h b/bta/op/bta_ops_int.h new file mode 100644 index 0000000..733b9ae --- /dev/null +++ b/bta/op/bta_ops_int.h @@ -0,0 +1,198 @@ +/***************************************************************************** +** +** Name: bta_ops_int.h +** +** Description: This is the private file for the object transfer +** server (OPS). +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ +#ifndef BTA_OPS_INT_H +#define BTA_OPS_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_op_api.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + + +/* OPS active obex operation (Valid in connected state) */ +#define OPS_OP_NONE 0 +#define OPS_OP_PULL_OBJ 1 +#define OPS_OP_PUSH_OBJ 2 + +/* state machine events */ +enum +{ + /* these events are handled by the state machine */ + BTA_OPS_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_OPS), + + BTA_OPS_API_ACCESSRSP_EVT, /* Response to an access request */ + BTA_OPS_API_CLOSE_EVT, /* Close API */ + BTA_OPS_CI_OPEN_EVT, /* Response to File Open request */ + BTA_OPS_CI_WRITE_EVT, /* Response to Write request */ + BTA_OPS_CI_READ_EVT, /* Response to Read request */ + BTA_OPS_OBX_CONN_EVT, /* OBX Channel Connect Request */ + BTA_OPS_OBX_DISC_EVT, /* OBX Channel Disconnect */ + BTA_OPS_OBX_ABORT_EVT, /* OBX_operation aborted */ + BTA_OPS_OBX_CLOSE_EVT, /* OBX Channel Disconnected (Link Lost) */ + BTA_OPS_OBX_PUT_EVT, /* Write file data or delete */ + BTA_OPS_OBX_GET_EVT, /* Read file data or folder listing */ + BTA_OPS_CLOSE_CMPL_EVT, /* Finished closing channel */ + + /* these events are handled outside the state machine */ + BTA_OPS_API_ENABLE_EVT +}; + +typedef UINT16 tBTA_OPS_INT_EVT; + +typedef UINT8 tBTA_OPS_STATE; + +/* data type for BTA_OPS_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + char name[BTA_SERVICE_NAME_LEN + 1]; + tBTA_OPS_CBACK *p_cback; + tBTA_OP_FMT_MASK formats; + UINT8 sec_mask; + BOOLEAN srm; + UINT8 app_id; +} tBTA_OPS_API_ENABLE; + +/* data type for BTA_OPS_API_ACCESSRSP_EVT */ +typedef struct +{ + BT_HDR hdr; + char *p_name; + tBTA_OP_OPER oper; + tBTA_OP_ACCESS flag; +} tBTA_OPS_API_ACCESSRSP; + +/* data type for all obex events + hdr.event contains the OPS 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_OPS_OBX_EVENT; + +/* union of all event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_OPS_API_ENABLE api_enable; + tBTA_OPS_API_ACCESSRSP api_access; + tBTA_OPS_OBX_EVENT obx_evt; + tBTA_FS_CI_OPEN_EVT open_evt; + tBTA_FS_CI_READ_EVT read_evt; + tBTA_FS_CI_WRITE_EVT write_evt; +} tBTA_OPS_DATA; + +/* OBX Response Packet Structure - Holds current response packet info */ +typedef struct +{ + BT_HDR *p_pkt; /* (Pull/Push) Holds the current OBX hdr for Push or Pull */ + UINT8 *p_start; /* (Pull/Push) Start of the Body of the packet */ + UINT16 offset; /* (Pull/Push) Contains the current offset into the Body (p_start) */ + UINT16 bytes_left; /* (Pull/Push) Holds bytes available left in Obx packet */ + BOOLEAN final_pkt; /* (Push) Holds the final bit of the Push packet */ +} tBTA_OPS_OBX_PKT; + +/* Power management state for OPS */ +#define BTA_OPS_PM_BUSY 0 +#define BTA_OPS_PM_IDLE 1 + +/* OPS control block */ +typedef struct +{ + tBTA_OPS_CBACK *p_cback; /* pointer to application callback function */ + char *p_name; /* Holds name of current operation */ + char *p_path; /* Holds path of current operation */ + tBTA_OPS_OBX_PKT obx; /* Holds the current OBX packet information */ + UINT32 sdp_handle; /* SDP record handle */ + UINT32 file_length; /* length of file being Push/Pull */ + 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 */ + BOOLEAN srm; /* TRUE, to use SIngle Response Mode */ + UINT8 scn; /* SCN of the OPP server */ + tBTA_OP_FMT_MASK formats; /* supported object formats */ + tBTA_OPS_STATE state; /* state machine state */ + tBTA_OP_FMT obj_fmt; /* file format of received object */ + UINT8 obx_oper; /* current active OBX operation PUSH OBJ, or PULL OBJ */ + UINT8 app_id; + tBTA_OP_OPER acc_active; /* op code when waiting for an access rsp (API) (0 not active) */ + BOOLEAN cout_active; /* TRUE when waiting for a call-in function */ + BOOLEAN aborting; /* TRUE when waiting for a call-in function */ + UINT8 pm_state; +} tBTA_OPS_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* OPS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_OPS_CB bta_ops_cb; +#else +extern tBTA_OPS_CB *bta_ops_cb_ptr; +#define bta_ops_cb (*bta_ops_cb_ptr) +#endif + + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +extern BOOLEAN bta_ops_hdl_event(BT_HDR *p_msg); +extern void bta_ops_sm_execute(tBTA_OPS_CB *p_cb, UINT16 event, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_cback (tOBX_HANDLE handle, tOBX_EVENT event, + tOBX_EVT_PARAM param, BT_HDR *p_pkt); + +/* action functions */ +extern void bta_ops_api_disable(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_api_accessrsp(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_api_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_ci_write(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_ci_read(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_ci_open(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_connect(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_disc(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_close(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_abort(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_put(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_obx_get(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_gasp_err_rsp(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_close_complete(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); + +/* object store */ +extern void bta_ops_init_get_obj(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); +extern void bta_ops_proc_get_obj(tBTA_OPS_CB *p_cb); +extern void bta_ops_proc_put_obj(BT_HDR *p_pkt); + +/* miscellaneous functions */ +extern void bta_ops_enable(tBTA_OPS_CB *p_cb, tBTA_OPS_API_ENABLE *p_data); +extern void bta_ops_get_obj_rsp(UINT8 rsp_code, UINT16 num_read); +extern void bta_ops_put_obj_rsp(UINT8 rsp_code); +extern void bta_ops_clean_getput(tBTA_OPS_CB *p_cb, BOOLEAN is_aborted); +extern void bta_ops_discard_data(UINT16 event, tBTA_OPS_DATA *p_data); +extern void bta_ops_req_app_access (tBTA_OP_OPER oper, tBTA_OPS_CB *p_cb); +extern tBTA_OP_FMT bta_ops_fmt_supported(char *p, tBTA_OP_FMT_MASK fmt_mask); + +#endif /* BTA_OPS_INT_H */ diff --git a/bta/op/bta_ops_main.c b/bta/op/bta_ops_main.c new file mode 100644 index 0000000..f98b43b --- /dev/null +++ b/bta/op/bta_ops_main.c @@ -0,0 +1,412 @@ +/***************************************************************************** +** +** Name: bta_ops_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 "bt_target.h" + +#if defined(BTA_OP_INCLUDED) && (BTA_OP_INCLUDED) + +#include <string.h> + +#include "bta_fs_api.h" +#include "bta_ops_int.h" +#include "gki.h" +#include "obx_api.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* state machine states */ +enum +{ + BTA_OPS_IDLE_ST = 0, /* Idle */ + BTA_OPS_LISTEN_ST, /* Listen - waiting for OBX/RFC connection */ + BTA_OPS_CONN_ST, /* Connected - OPP Session is active */ + BTA_OPS_CLOSING_ST /* Closing is in progress */ +}; + +/* state machine action enumeration list */ +enum +{ + BTA_OPS_API_DISABLE, + BTA_OPS_API_ACCESSRSP, + BTA_OPS_API_CLOSE, + BTA_OPS_CI_WRITE, + BTA_OPS_CI_READ, + BTA_OPS_CI_OPEN, + BTA_OPS_OBX_CONNECT, + BTA_OPS_OBX_DISC, + BTA_OPS_OBX_CLOSE, + BTA_OPS_OBX_ABORT, + BTA_OPS_OBX_PUT, + BTA_OPS_OBX_GET, + BTA_OPS_CLOSE_COMPLETE, + BTA_OPS_IGNORE +}; + +/* type for action functions */ +typedef void (*tBTA_OPS_ACTION)(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data); + +/* action function list */ +const tBTA_OPS_ACTION bta_ops_action[] = +{ + bta_ops_api_disable, + bta_ops_api_accessrsp, + bta_ops_api_close, + bta_ops_ci_write, + bta_ops_ci_read, + bta_ops_ci_open, + bta_ops_obx_connect, + bta_ops_obx_disc, + bta_ops_obx_close, + bta_ops_obx_abort, + bta_ops_obx_put, + bta_ops_obx_get, + bta_ops_close_complete +}; + + +/* state table information */ +#define BTA_OPS_ACTIONS 1 /* number of actions */ +#define BTA_OPS_NEXT_STATE 1 /* position of next state */ +#define BTA_OPS_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_ops_st_idle[][BTA_OPS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_IDLE_ST}, +/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_IGNORE, BTA_OPS_IDLE_ST}, +/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_IDLE_ST}, +}; + +/* state table for obex/rfcomm connection state */ +static const UINT8 bta_ops_st_listen[][BTA_OPS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_API_DISABLE, BTA_OPS_IDLE_ST}, +/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_CI_OPEN_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_CI_WRITE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_CI_READ_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_OBX_CONN_EVT */ {BTA_OPS_OBX_CONNECT, BTA_OPS_CONN_ST}, +/* BTA_OPS_OBX_DISC_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_OBX_ABORT_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_OBX_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_OBX_PUT_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_OBX_GET_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_CLOSE_CMPL_EVT */ {BTA_OPS_IGNORE, BTA_OPS_LISTEN_ST} +}; + +/* state table for open state */ +static const UINT8 bta_ops_st_connected[][BTA_OPS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_API_DISABLE, BTA_OPS_IDLE_ST}, +/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_API_ACCESSRSP, BTA_OPS_CONN_ST}, +/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_API_CLOSE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_CI_OPEN_EVT */ {BTA_OPS_CI_OPEN, BTA_OPS_CONN_ST}, +/* BTA_OPS_CI_WRITE_EVT */ {BTA_OPS_CI_WRITE, BTA_OPS_CONN_ST}, +/* BTA_OPS_CI_READ_EVT */ {BTA_OPS_CI_READ, BTA_OPS_CONN_ST}, +/* BTA_OPS_OBX_CONN_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CONN_ST}, +/* BTA_OPS_OBX_DISC_EVT */ {BTA_OPS_OBX_DISC, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_ABORT_EVT */ {BTA_OPS_OBX_ABORT, BTA_OPS_CONN_ST}, +/* BTA_OPS_OBX_CLOSE_EVT */ {BTA_OPS_OBX_CLOSE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_PUT_EVT */ {BTA_OPS_OBX_PUT, BTA_OPS_CONN_ST}, +/* BTA_OPS_OBX_GET_EVT */ {BTA_OPS_OBX_GET, BTA_OPS_CONN_ST}, +/* BTA_OPS_CLOSE_CMPL_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CONN_ST} +}; + +/* state table for closing state */ +static const UINT8 bta_ops_st_closing[][BTA_OPS_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_OPS_API_DISABLE_EVT */ {BTA_OPS_API_DISABLE, BTA_OPS_IDLE_ST}, +/* BTA_OPS_API_ACCESSRSP_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_API_CLOSE_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_CI_OPEN_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_CI_WRITE_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_CI_READ_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST}, +/* BTA_OPS_OBX_CONN_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_DISC_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_ABORT_EVT */ {BTA_OPS_OBX_ABORT, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_CLOSE_EVT */ {BTA_OPS_OBX_CLOSE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_PUT_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_OBX_GET_EVT */ {BTA_OPS_IGNORE, BTA_OPS_CLOSING_ST}, +/* BTA_OPS_CLOSE_CMPL_EVT */ {BTA_OPS_CLOSE_COMPLETE, BTA_OPS_LISTEN_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_OPS_ST_TBL)[BTA_OPS_NUM_COLS]; + +/* state table */ +const tBTA_OPS_ST_TBL bta_ops_st_tbl[] = +{ + bta_ops_st_idle, + bta_ops_st_listen, + bta_ops_st_connected, + bta_ops_st_closing +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* OPS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_OPS_CB bta_ops_cb; +#endif + +#if BTA_OPS_DEBUG == TRUE +static char *ops_evt_code(tBTA_OPS_INT_EVT evt_code); +static char *ops_state_code(tBTA_OPS_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_ops_sm_execute +** +** Description State machine event handling function for OPS +** +** +** Returns void +** +*******************************************************************************/ +void bta_ops_sm_execute(tBTA_OPS_CB *p_cb, UINT16 event, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_ST_TBL state_table; + UINT8 action; + int i; +#if BTA_OPS_DEBUG == TRUE + tBTA_OPS_STATE in_state = bta_ops_cb.state; + UINT16 in_event = event; + APPL_TRACE_EVENT3("OPS Event Handler: State 0x%02x [%s], Event [%s]", in_state, + ops_state_code(in_state), + ops_evt_code(event)); +#endif + + /* look up the state table for the current state */ + state_table = bta_ops_st_tbl[p_cb->state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->state = state_table[event][BTA_OPS_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_OPS_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_OPS_IGNORE) + { + (*bta_ops_action[action])(p_cb, p_data); + } + else + { + /* discard ops data */ + bta_ops_discard_data(p_data->hdr.event, p_data); + break; + } + } + +#if BTA_OPS_DEBUG == TRUE + if (in_state != bta_ops_cb.state) + { + APPL_TRACE_DEBUG3("OPS State Change: [%s] -> [%s] after Event [%s]", + ops_state_code(in_state), + ops_state_code(bta_ops_cb.state), + ops_evt_code(in_event)); + } +#endif +} + +/******************************************************************************* +** +** Function bta_ops_api_enable +** +** Description Handle an api enable event. This function enables the OP +** Server by opening an Obex/Rfcomm channel and placing it into +** listen mode. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ops_api_enable(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_API_ENABLE *p_enable = &p_data->api_enable; + + /* initialize control block */ + memset(p_cb, 0, sizeof(tBTA_OPS_CB)); + p_cb->p_cback = p_enable->p_cback; + p_cb->app_id = p_enable->app_id; + p_cb->srm = p_enable->srm; + p_cb->fd = BTA_FS_INVALID_FD; + + bta_ops_cb.state = BTA_OPS_LISTEN_ST; + + /* call enable action function */ + bta_ops_enable(p_cb, p_enable); +} + +/******************************************************************************* +** +** Function bta_ops_hdl_event +** +** Description File transfer server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_ops_hdl_event(BT_HDR *p_msg) +{ +#if BTA_OPS_DEBUG == TRUE + tBTA_OPS_STATE in_state = bta_ops_cb.state; +#endif + + switch (p_msg->event) + { + case BTA_OPS_API_ENABLE_EVT: +#if BTA_OPS_DEBUG == TRUE + APPL_TRACE_EVENT3("OPS Event Handler: State 0x%02x [%s], Event [%s]", in_state, + ops_state_code(in_state), + ops_evt_code(p_msg->event)); +#endif + bta_ops_api_enable(&bta_ops_cb, (tBTA_OPS_DATA *) p_msg); + +#if BTA_OPS_DEBUG == TRUE + if (in_state != bta_ops_cb.state) + { + APPL_TRACE_DEBUG3("OPS State Change: [%s] -> [%s] after Event [%s]", + ops_state_code(in_state), + ops_state_code(bta_ops_cb.state), + ops_evt_code(p_msg->event)); + } +#endif + break; + + default: + + bta_ops_sm_execute(&bta_ops_cb, p_msg->event, (tBTA_OPS_DATA *) p_msg); + + if ( bta_ops_cb.state == BTA_OPS_CONN_ST ) + { + if (( bta_ops_cb.pm_state == BTA_OPS_PM_IDLE ) + &&( bta_ops_cb.obx_oper != OPS_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA OPS informs DM/PM busy state"); + bta_sys_busy( BTA_ID_OPS ,bta_ops_cb.app_id, bta_ops_cb.bd_addr); + bta_ops_cb.pm_state = BTA_OPS_PM_BUSY; + } + else if (( bta_ops_cb.pm_state == BTA_OPS_PM_BUSY ) + &&( bta_ops_cb.obx_oper == OPS_OP_NONE )) + { + /* inform power manager */ + APPL_TRACE_DEBUG0("BTA OPS informs DM/PM idle state"); + bta_sys_idle( BTA_ID_OPS ,bta_ops_cb.app_id, bta_ops_cb.bd_addr); + bta_ops_cb.pm_state = BTA_OPS_PM_IDLE; + } + } + else if ( bta_ops_cb.state == BTA_OPS_LISTEN_ST ) + { + /* initialize power management state */ + bta_ops_cb.pm_state = BTA_OPS_PM_BUSY; + } + + break; + } + + return (TRUE); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_OPS_DEBUG == TRUE + +/******************************************************************************* +** +** Function ops_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *ops_evt_code(tBTA_OPS_INT_EVT evt_code) +{ + switch(evt_code) + { + case BTA_OPS_API_DISABLE_EVT: + return "BTA_OPS_API_DISABLE_EVT"; + case BTA_OPS_API_ACCESSRSP_EVT: + return "BTA_OPS_API_ACCESSRSP_EVT"; + case BTA_OPS_API_CLOSE_EVT: + return "BTA_OPS_API_CLOSE_EVT"; + case BTA_OPS_CI_OPEN_EVT: + return "BTA_OPS_CI_OPEN_EVT"; + case BTA_OPS_CI_WRITE_EVT: + return "BTA_OPS_CI_WRITE_EVT"; + case BTA_OPS_CI_READ_EVT: + return "BTA_OPS_CI_READ_EVT"; + case BTA_OPS_OBX_CONN_EVT: + return "BTA_OPS_OBX_CONN_EVT"; + case BTA_OPS_OBX_DISC_EVT: + return "BTA_OPS_OBX_DISC_EVT"; + case BTA_OPS_OBX_ABORT_EVT: + return "BTA_OPS_OBX_ABORT_EVT"; + case BTA_OPS_OBX_CLOSE_EVT: + return "BTA_OPS_OBX_CLOSE_EVT"; + case BTA_OPS_OBX_PUT_EVT: + return "BTA_OPS_OBX_PUT_EVT"; + case BTA_OPS_OBX_GET_EVT: + return "BTA_OPS_OBX_GET_EVT"; + case BTA_OPS_CLOSE_CMPL_EVT: + return "BTA_OPS_CLOSE_CMPL_EVT"; + case BTA_OPS_API_ENABLE_EVT: + return "BTA_OPS_API_ENABLE_EVT"; + default: + return "unknown OPS event code"; + } +} + +/******************************************************************************* +** +** Function ops_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *ops_state_code(tBTA_OPS_STATE state_code) +{ + switch(state_code) + { + case BTA_OPS_IDLE_ST: + return "BTA_OPS_IDLE_ST"; + case BTA_OPS_LISTEN_ST: + return "BTA_OPS_LISTEN_ST"; + case BTA_OPS_CONN_ST: + return "BTA_OPS_CONN_ST"; + case BTA_OPS_CLOSING_ST: + return "BTA_OPS_CLOSING_ST"; + default: + return "unknown OPS state code"; + } +} + +#endif /* Debug Functions */ +#endif /* BTA_OP_INCLUDED */ diff --git a/bta/op/bta_ops_utils.c b/bta/op/bta_ops_utils.c new file mode 100644 index 0000000..eccc1e7 --- /dev/null +++ b/bta/op/bta_ops_utils.c @@ -0,0 +1,487 @@ +/***************************************************************************** +** +** Name: bta_ops_utils.c +** +** Description: This file implements object store functions for the +** object transfer server. +** +** Copyright (c) 2003-2011, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +** +*****************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_OP_INCLUDED) && (BTA_OP_INCLUDED) + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "bta_fs_api.h" +#include "bta_ops_int.h" +#include "bta_fs_co.h" +#include "gki.h" +#include "utl.h" +#include "bd.h" + +/******************************************************************************* +** Constants +*******************************************************************************/ + +/******************************************************************************* +** Local Function Prototypes +*******************************************************************************/ +static int bta_ops_stricmp (const char *p_str1, const char *p_str2); + +/******************************************************************************* +* Exported Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function bta_ops_init_get_obj +** +** Description Processes a begin object pull request. +** +** Returns void +** +*******************************************************************************/ +void bta_ops_init_get_obj(tBTA_OPS_CB *p_cb, tBTA_OPS_DATA *p_data) +{ + tBTA_OPS_OBX_EVENT *p_evt = &p_data->obx_evt; + UINT8 rsp_code = OBX_RSP_FORBIDDEN; + UINT16 len; + UINT8 *p_type; + UINT16 name_len; + + /* Type Hdr must be present */ + if (OBX_ReadTypeHdr(p_evt->p_pkt, &p_type, &len)) + { + /* Type Hdr must be correct */ + if (!bta_ops_stricmp((const char *)p_type, "text/x-vcard")) + { + /* Erratum 385 - original OPP spec says "Name Header must not be used." + * errara says "Name Header must be empty" + * Be a forgiving OPP server, allow either way */ + name_len = OBX_ReadHdrLen(p_evt->p_pkt, OBX_HI_NAME); + if((name_len == OBX_INVALID_HDR_LEN) ||/* no name header */ + (name_len == 3) /* name header is empty */ ) + { + p_cb->obx.p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, + /*p_cb->peer_mtu*/OBX_CMD_POOL_SIZE); + p_cb->p_path = (char *)GKI_getbuf((UINT16)(p_bta_fs_cfg->max_path_len + 1)); + + if (p_cb->p_path && p_cb->obx.p_pkt) + { + p_cb->p_path[0] = '\0'; + p_cb->p_name = p_cb->p_path; + p_cb->obx_oper = OPS_OP_PULL_OBJ; + p_cb->obj_fmt = BTA_OP_VCARD21_FMT; + p_cb->file_length = BTA_FS_LEN_UNKNOWN; + + /* Notify the appl that a pull default card has been requested */ + bta_ops_req_app_access (BTA_OP_OPER_PULL, p_cb); + rsp_code = OBX_RSP_CONTINUE; + } + else + rsp_code = OBX_RSP_INTRNL_SRVR_ERR; + } + } + } + + /* Error has been detected; respond with error code */ + if (rsp_code != OBX_RSP_CONTINUE) + { + utl_freebuf((void**)&p_cb->obx.p_pkt); + utl_freebuf((void**)&p_cb->p_path); + p_cb->p_name = NULL; + OBX_GetRsp(p_evt->handle, rsp_code, (BT_HDR *)NULL); + } +} + +/******************************************************************************* +** +** Function bta_ops_proc_get_obj +** +** Description Processes a continuation packet for pulling a vcard. +** Builds a response packet and initiates a read into it. +** +** Returns void +** +*******************************************************************************/ +void bta_ops_proc_get_obj(tBTA_OPS_CB *p_cb) +{ + tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx; + + /* Allocate a new OBX packet */ + if ((p_obx->p_pkt = (BT_HDR *)OBX_HdrInit(p_cb->obx_handle, + /*p_cb->peer_mtu*/OBX_LRG_DATA_POOL_SIZE)) != NULL) + { + /* 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); + + p_cb->cout_active = TRUE; + bta_fs_co_read(p_cb->fd, &p_obx->p_start[p_obx->offset], + p_obx->bytes_left, BTA_OPS_CI_READ_EVT, 0, p_cb->app_id); + } + else + bta_ops_get_obj_rsp(OBX_RSP_INTRNL_SRVR_ERR, 0); +} + +/******************************************************************************* +** +** Function bta_ops_proc_put_obj +** +** Description Processes a Push Object Operation. +** Initiates the opening of an object for writing, or continues +** with a new Obx packet of data (continuation). +** +** Parameters p_pkt - Pointer to the OBX Put request +** +** Returns void +** +*******************************************************************************/ +void bta_ops_proc_put_obj(BT_HDR *p_pkt) +{ + tBTA_OPS_CB *p_cb = &bta_ops_cb; + tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx; + UINT8 num_hdrs; + BOOLEAN endpkt; + + p_obx->p_pkt = p_pkt; + + p_obx->offset = 0; /* Initial offset into OBX data */ + /* 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) + { + p_cb->cout_active = TRUE; + bta_fs_co_write(p_cb->fd, &p_obx->p_start[p_obx->offset], + p_obx->bytes_left, BTA_OPS_CI_WRITE_EVT, 0, p_cb->app_id); + } + else + { + bta_ops_clean_getput(p_cb, TRUE); + bta_ops_put_obj_rsp(OBX_RSP_BAD_REQUEST); + } +} + +/******************************************************************************* +** +** Function bta_ops_get_obj_rsp +** +** Description Finishes up the end body of the object get, and sends out the +** OBX response +** +** Returns void +** +*******************************************************************************/ +void bta_ops_get_obj_rsp(UINT8 rsp_code, UINT16 num_read) +{ + tBTA_OPS_CB *p_cb = &bta_ops_cb; + tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_OPS_PROGRESS 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("OPS 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.bytes = num_read; + param.obj_size = p_cb->file_length; + param.operation = BTA_OP_OPER_PULL; + p_cb->p_cback(BTA_OPS_PROGRESS_EVT, (tBTA_OPS *)¶m); + } + } + else + p_cb->obx_oper = OPS_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_ops_clean_getput(p_cb, FALSE); +} + +/******************************************************************************* +** +** Function bta_ops_put_obj_rsp +** +** Description Responds to a put request, and closes the object if finished +** +** Returns void +** +*******************************************************************************/ +void bta_ops_put_obj_rsp(UINT8 rsp_code) +{ + tBTA_OPS_CB *p_cb = &bta_ops_cb; + tBTA_OPS_OBX_PKT *p_obx = &p_cb->obx; + tBTA_OPS_PROGRESS param; + tBTA_OPS_OBJECT object; + + /* Finished with input packet */ + utl_freebuf((void**)&p_obx->p_pkt); + + if (rsp_code == OBX_RSP_OK) + { + /* Update application if object data was transferred */ + if (p_obx->bytes_left) + { + param.bytes = p_obx->bytes_left; + param.obj_size = p_cb->file_length; + param.operation = BTA_OP_OPER_PUSH; + p_cb->p_cback(BTA_OPS_PROGRESS_EVT, (tBTA_OPS *)¶m); + } + + /* If not end of object put, set the continue response */ + if (!p_obx->final_pkt) + rsp_code = OBX_RSP_CONTINUE; + else /* Done - free the allocated memory */ + { + /* callback to app with object */ + object.format = p_cb->obj_fmt; + object.p_name = p_cb->p_name; + + bta_ops_clean_getput(p_cb, FALSE); + p_cb->p_cback(BTA_OPS_OBJECT_EVT, (tBTA_OPS *) &object); + + } + } + else + p_cb->obx_oper = OPS_OP_NONE; + + OBX_PutRsp(p_cb->obx_handle, rsp_code, (BT_HDR *)NULL); +} + +/******************************************************************************* +** +** Function bta_ops_req_app_access +** +** Description Sends an access request event to the application. +** +** Returns void +** +*******************************************************************************/ +void bta_ops_req_app_access (tBTA_OP_OPER oper, tBTA_OPS_CB *p_cb) +{ + tBTA_OPS_ACCESS *p_acc_evt; + char *p_devname; + UINT16 len; + + /* Notify the application that a put or get file has been requested */ + if ((p_acc_evt = (tBTA_OPS_ACCESS *)GKI_getbuf(sizeof(tBTA_OPS_ACCESS))) != NULL) + { + memset(p_acc_evt, 0, sizeof(tBTA_OPS_ACCESS)); + p_acc_evt->p_name = p_cb->p_name; + p_acc_evt->size = p_cb->file_length; + p_acc_evt->oper = p_cb->acc_active = oper; + p_acc_evt->format = p_cb->obj_fmt; + 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(tBTM_BD_NAME), p_devname, BTM_MAX_REM_BD_NAME_LEN); + + /* Only pass the object type if Push operation */ + if (oper == BTA_OP_OPER_PUSH) + { + if (!OBX_ReadTypeHdr(p_cb->obx.p_pkt, (UINT8 **)&p_acc_evt->p_type, &len)) + p_acc_evt->p_type = NULL; + } + + if (p_acc_evt->p_type) + { + APPL_TRACE_EVENT3("OPS Access Request...Name [%s], Oper [%d], Type [%s]", + p_cb->p_name, oper, p_acc_evt->p_type); + } + else + { + APPL_TRACE_EVENT2("OPS Access Request...Name [%s], Oper [%d]", + p_cb->p_name, oper); + } + + p_cb->p_cback(BTA_OPS_ACCESS_EVT, (tBTA_OPS *)p_acc_evt); + GKI_freebuf(p_acc_evt); + } +} + +/******************************************************************************* +** +** Function bta_ops_clean_getput +** +** Description Cleans up the get/put resources and control block +** +** Returns void +** +*******************************************************************************/ +void bta_ops_clean_getput(tBTA_OPS_CB *p_cb, BOOLEAN is_aborted) +{ + tBTA_FS_CO_STATUS status; + + /* 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 (is_aborted && p_cb->obx_oper == OPS_OP_PUSH_OBJ) + { + status = bta_fs_co_unlink(p_cb->p_path, p_cb->app_id); + APPL_TRACE_WARNING2("OPS: Remove ABORTED Push File Operation [%s], status 0x%02x", p_cb->p_path, status); + } + } + + utl_freebuf((void**)&p_cb->p_path); + p_cb->p_name = NULL; + + p_cb->obx_oper = OPS_OP_NONE; + p_cb->obx.bytes_left = 0; + p_cb->file_length = BTA_FS_LEN_UNKNOWN; + p_cb->acc_active = 0; + p_cb->aborting = FALSE; +} + +/******************************************************************************* +** +** Function bta_ops_fmt_supported +** +** Description This function determines the file type from a file name +** and checks if the file type is supported. +** +** +** Returns Format type value or zero if format unsupported. +** +*******************************************************************************/ +tBTA_OP_FMT bta_ops_fmt_supported(char *p, tBTA_OP_FMT_MASK fmt_mask) +{ + char *p_suffix; + tBTA_OP_FMT fmt = BTA_OP_OTHER_FMT; + + /* scan to find file suffix */ + if ((p_suffix = strrchr(p, '.')) != NULL) + { + p_suffix++; + if (bta_ops_stricmp (p_suffix, "vcf") == 0) + { + fmt = BTA_OP_VCARD21_FMT; + } + else if (bta_ops_stricmp (p_suffix, "vcd") == 0) + { + fmt = BTA_OP_VCARD30_FMT; + } + else if (bta_ops_stricmp (p_suffix, "vcs") == 0) + { + fmt = BTA_OP_VCAL_FMT; + } + else if (bta_ops_stricmp (p_suffix, "ics") == 0) + { + fmt = BTA_OP_ICAL_FMT; + } + else if (bta_ops_stricmp (p_suffix, "vmg") == 0) + { + fmt = BTA_OP_VMSG_FMT; + } + else if (bta_ops_stricmp (p_suffix, "vnt") == 0) + { + fmt = BTA_OP_VNOTE_FMT; + } + } + + /* see if supported */ + if (fmt == BTA_OP_OTHER_FMT) + { + if (!(fmt_mask & BTA_OP_ANY_MASK)) + fmt = 0; /* Other types not supported */ + } + else + { + if (!((1 << (fmt - 1)) & fmt_mask)) + fmt = 0; + } + + return fmt; +} + +/******************************************************************************* +** +** Function bta_ops_discard_data +** +** Description frees the data +** +** Returns void +** +*******************************************************************************/ +void bta_ops_discard_data(UINT16 event, tBTA_OPS_DATA *p_data) +{ + switch(event) + { + case BTA_OPS_OBX_CONN_EVT: + case BTA_OPS_OBX_DISC_EVT: + case BTA_OPS_OBX_ABORT_EVT: + case BTA_OPS_OBX_CLOSE_EVT: + case BTA_OPS_OBX_PUT_EVT: + case BTA_OPS_OBX_GET_EVT: + utl_freebuf((void**)&p_data->obx_evt.p_pkt); + break; + + default: + /*Nothing to free*/ + break; + } +} + +/******************************************************************************* +* Static Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function bta_ops_stricmp +** +** Description Used to compare type header +** +** +** Returns void +** +*******************************************************************************/ +static int bta_ops_stricmp (const char *p_str1, const char *p_str2) +{ + UINT16 i; + UINT16 cmplen; + + if (!p_str1 || !p_str2) + return (1); + + cmplen = strlen(p_str1); + if (cmplen != strlen(p_str2)) + return (1); + + for (i = 0; i < cmplen; i++) + { + if (toupper(p_str1[i]) != toupper(p_str2[i])) + return (i+1); + } + + return 0; +} +#endif /* BTA_OP_INCLUDED */ |