From e03b79ab681d604ecef6b0fb3c2fdc48ecd56a55 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Wed, 26 Sep 2018 16:45:03 +0200 Subject: [PATCH] pbap_client: implement pbap_lookup_by_number --- example/Makefile.inc | 4 +- example/pbap_client_demo.c | 8 ++- src/classic/pbap_client.c | 108 ++++++++++++++++++++++++++++++++++--- src/classic/pbap_client.h | 10 +++- 4 files changed, 120 insertions(+), 10 deletions(-) diff --git a/example/Makefile.inc b/example/Makefile.inc index 0b0e36f06..c3c9c10d2 100644 --- a/example/Makefile.inc +++ b/example/Makefile.inc @@ -9,6 +9,7 @@ VPATH += ${BTSTACK_ROOT}/3rd-party/md5 VPATH += ${BTSTACK_ROOT}/3rd-party/micro-ecc VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder//srce +VPATH += ${BTSTACK_ROOT}/3rd-party/yxml CFLAGS += -I. CFLAGS += -I${BTSTACK_ROOT}/src/ble @@ -19,6 +20,7 @@ CFLAGS += -I${BTSTACK_ROOT}/3rd-party/md5 CFLAGS += -I${BTSTACK_ROOT}/3rd-party/micro-ecc CFLAGS += -I${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/include CFLAGS += -I${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/include +CFLAGS += -I${BTSTACK_ROOT}/3rd-party/yxml # for CVSD/SBC PLC LDFLAGS += -lm @@ -194,7 +196,7 @@ ant_test: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ant_test.c sdp_rfcomm_query: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${PAN_OBJ} ${SDP_CLIENT} sdp_rfcomm_query.c ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ -pbap_client_demo: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} md5.o obex_iterator.c goep_client.c pbap_client.c pbap_client_demo.c +pbap_client_demo: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} md5.o obex_iterator.o goep_client.o yxml.o pbap_client.o pbap_client_demo.o ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ sdp_general_query: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} sdp_general_query.c diff --git a/example/pbap_client_demo.c b/example/pbap_client_demo.c index 4384546e4..e5f53426b 100644 --- a/example/pbap_client_demo.c +++ b/example/pbap_client_demo.c @@ -72,7 +72,9 @@ static bd_addr_t remote_addr; // Nexus 7 "30-85-A9-54-2E-78" // iPhone SE "BC:EC:5D:E6:15:03" // PTS "001BDC080AA5" -static char * remote_addr_string = "001BDC080AA5"; +static char * remote_addr_string = "BC:EC:5D:E6:15:03"; + +static char * phone_number = "911"; static btstack_packet_callback_registration_t hci_event_callback_registration; static uint16_t pbap_cid; @@ -92,6 +94,7 @@ static void show_usage(void){ printf("d - get phonebook size\n"); printf("e - pull phonebook\n"); printf("f - disconnnect\n"); + printf("g - Lookup contact with number '%s'\n", phone_number); printf("p - authenticate using password '0000'\n"); printf("\n"); } @@ -119,6 +122,9 @@ static void stdin_process(char c){ case 'f': pbap_disconnect(pbap_cid); break; + case 'g': + pbap_lookup_by_number(pbap_cid, phone_number); + break; case 'p': pbap_authentication_password(pbap_cid, "0000"); break; diff --git a/src/classic/pbap_client.c b/src/classic/pbap_client.c index a5a487474..a1ed1eab4 100644 --- a/src/classic/pbap_client.c +++ b/src/classic/pbap_client.c @@ -75,16 +75,23 @@ #include "classic/sdp_client_rfcomm.h" #include "btstack_event.h" #include "md5.h" +#include "yxml.h" #include "classic/obex.h" #include "classic/obex_iterator.h" #include "classic/goep_client.h" #include "classic/pbap_client.h" +#define PBAP_MAX_PHONE_NUMBER_LEN 30 + // 796135f0-f0c5-11d8-0966- 0800200c9a66 uint8_t pbap_uuid[] = { 0x79, 0x61, 0x35, 0xf0, 0xf0, 0xc5, 0x11, 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66}; -const char * pbap_type = "x-bt/phonebook"; -const char * pbap_name = "pb.vcf"; + +const char * pbap_phonebook_type = "x-bt/phonebook"; +const char * pbap_phonebook_name = "pb.vcf"; + +const char * pbap_vcard_listing_type = "x-bt/vcard-listing"; +const char * pbap_vcard_listing_name = "pb"; typedef enum { PBAP_INIT = 0, @@ -107,6 +114,10 @@ typedef enum { PBAP_W4_SET_PATH_ELEMENT_COMPLETE, PBAP_W2_GET_PHONEBOOK_SIZE, PBAP_W4_GET_PHONEBOOK_SIZE_COMPLETE, + // + PBAP_W2_GET_CARD_LIST, + PBAP_W4_GET_CARD_LIST_COMPLETE, + } pbap_state_t; typedef struct pbap_client { @@ -118,10 +129,13 @@ typedef struct pbap_client { uint16_t goep_cid; btstack_packet_handler_t client_handler; const char * current_folder; + const char * phone_number; uint16_t set_path_offset; uint8_t authentication_options; uint16_t authentication_nonce[16]; const char * authentication_password; + yxml_t xml_parser; + uint8_t xml_buffer[50]; } pbap_client_t; static pbap_client_t _pbap_client; @@ -213,9 +227,10 @@ static void pbap_handle_can_send_now(void){ uint8_t path_element[20]; uint16_t path_element_start; uint16_t path_element_len; - uint8_t application_parameters[20]; + uint8_t application_parameters[PBAP_MAX_PHONE_NUMBER_LEN + 10]; uint8_t challenge_response[36]; int i; + uint16_t phone_number_len; MD5_CTX md5_ctx; @@ -261,8 +276,8 @@ static void pbap_handle_can_send_now(void){ case PBAP_W2_PULL_PHONEBOOK: case PBAP_W2_GET_PHONEBOOK_SIZE: goep_client_create_get_request(pbap_client->goep_cid); - goep_client_add_header_type(pbap_client->goep_cid, pbap_type); - goep_client_add_header_name(pbap_client->goep_cid, pbap_name); + goep_client_add_header_type(pbap_client->goep_cid, pbap_phonebook_type); + goep_client_add_header_name(pbap_client->goep_cid, pbap_phonebook_name); if (pbap_client->state == PBAP_W2_GET_PHONEBOOK_SIZE){ // Regular TLV wih 1-byte len application_parameters[0] = PBAP_APPLICATION_PARAMETER_MAX_LIST_COUNT; @@ -278,6 +293,25 @@ static void pbap_handle_can_send_now(void){ // send packet goep_client_execute(pbap_client->goep_cid); break; + case PBAP_W2_GET_CARD_LIST: + goep_client_create_get_request(pbap_client->goep_cid); + goep_client_add_header_type(pbap_client->goep_cid, pbap_vcard_listing_type); + goep_client_add_header_name(pbap_client->goep_cid, pbap_vcard_listing_name); + // Regular TLV wih 1-byte len + i = 0; + phone_number_len = btstack_min(PBAP_MAX_PHONE_NUMBER_LEN, strlen(pbap_client->phone_number)); + application_parameters[i++] = PBAP_APPLICATION_PARAMETER_SEARCH_VALUE; + application_parameters[i++] = phone_number_len; + memcpy(&application_parameters[i], pbap_client->phone_number, phone_number_len); + i += phone_number_len; + application_parameters[i++] = PBAP_APPLICATION_PARAMETER_SEARCH_PROPERTY; + application_parameters[i++] = 1; + application_parameters[i++] = 0x01; // Number + goep_client_add_header_application_parameters(pbap_client->goep_cid, i, &application_parameters[0]); + pbap_client->state = PBAP_W4_GET_CARD_LIST_COMPLETE; + // send packet + goep_client_execute(pbap_client->goep_cid); + break; case PBAP_W2_SET_PATH_ROOT: goep_client_create_set_path_request(pbap_client->goep_cid, 1 << 1); // Don’t create directory // On Android 4.2 Cyanogenmod, using "" as path fails @@ -392,9 +426,7 @@ static void pbap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * break; case GOEP_DATA_PACKET: // TODO: handle chunked data -#if 1 // obex_dump_packet(goep_client_get_request_opcode(pbap_client->goep_cid), packet, size); -#endif switch (pbap_client->state){ case PBAP_W4_CONNECT_RESPONSE: switch (packet[0]){ @@ -495,6 +527,59 @@ static void pbap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * } pbap_client_emit_phonebook_size_event(pbap_client, OBEX_UNKNOWN_ERROR, 0); break; + case PBAP_W4_GET_CARD_LIST_COMPLETE: + printf("PBAP_W4_GET_CARD_LIST_COMPLETE\n"); + if (packet[0] == OBEX_RESP_CONTINUE){ + pbap_client->state = PBAP_W2_GET_CARD_LIST; + goep_client_request_can_send_now(pbap_client->goep_cid); + } else if (packet[0] == OBEX_RESP_SUCCESS){ + for (obex_iterator_init_with_response_packet(&it, goep_client_get_request_opcode(pbap_client->goep_cid), packet, size); obex_iterator_has_more(&it) ; obex_iterator_next(&it)){ + uint8_t hi = obex_iterator_get_hi(&it); + if (hi == OBEX_HEADER_END_OF_BODY){ + uint16_t data_len = obex_iterator_get_data_len(&it); + const uint8_t * data = obex_iterator_get_data(&it); + // now try parsing it + yxml_init(&pbap_client->xml_parser, pbap_client->xml_buffer, sizeof(pbap_client->xml_buffer)); + int card_found = 0; + int name_found = 0; + char name[32]; + while (data_len--){ + yxml_ret_t r = yxml_parse(&pbap_client->xml_parser, *data++); + switch (r){ + case YXML_ELEMSTART: + card_found = strcmp("card", pbap_client->xml_parser.elem) == 0; + break; + case YXML_ELEMEND: + card_found = 0; + break; + case YXML_ATTRSTART: + if (!card_found) break; + name_found = strcmp("name", pbap_client->xml_parser.attr) == 0; + break; + case YXML_ATTRVAL: + if (!name_found) break; + // "In UTF-8, characters from the U+0000..U+10FFFF range (the UTF-16 accessible range) are encoded using sequences of 1 to 4 octets." + if (strlen(name) + 4 + 1 >= sizeof(name)) break; + strcat(name, pbap_client->xml_parser.data); + break; + case YXML_ATTREND: + if (!name_found) break; + printf("Name: '%s'\n", name); + name_found = 0; + break; + default: + break; + } + } + // + pbap_client->state = PBAP_CONNECTED; + } + } + + } else { + // ? + } + break; default: break; } @@ -562,3 +647,12 @@ uint8_t pbap_authentication_password(uint16_t pbap_cid, const char * password){ goep_client_request_can_send_now(pbap_client->goep_cid); return 0; } + +uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number){ + UNUSED(pbap_cid); + if (pbap_client->state != PBAP_CONNECTED) return BTSTACK_BUSY; + pbap_client->state = PBAP_W2_GET_CARD_LIST; + pbap_client->phone_number = phone_number; + goep_client_request_can_send_now(pbap_client->goep_cid); + return 0; +} diff --git a/src/classic/pbap_client.h b/src/classic/pbap_client.h index 0cf4b6973..77c481d50 100644 --- a/src/classic/pbap_client.h +++ b/src/classic/pbap_client.h @@ -94,7 +94,15 @@ uint8_t pbap_get_phonebook_size(uint16_t pbap_cid); * @param pbap_cid * @return status */ - uint8_t pbap_pull_phonebook(uint16_t pbap_cid); +uint8_t pbap_pull_phonebook(uint16_t pbap_cid); + +/** + * @brief Lookup contact(s) by phone number + * @param pbap_cid + * @param phone_number + * @return status + */ +uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number); /* API_END */