map_client: set path, get folders and messages, draft impl

This commit is contained in:
Milanka Ringwald 2019-03-08 22:45:32 +01:00
parent 47e764c40c
commit 0cb4d92c9e
3 changed files with 235 additions and 11 deletions

View File

@ -74,9 +74,18 @@ typedef enum {
MAP_CONNECT_RESPONSE_RECEIVED,
MAP_CONNECTED,
MAP_W2_SET_PATH_ROOT,
MAP_W4_SET_PATH_ROOT_COMPLETE,
MAP_W2_SET_PATH_ELEMENT,
MAP_W4_SET_PATH_ELEMENT_COMPLETE,
MAP_W2_SEND_GET_FOLDERS,
MAP_W4_FOLDERS,
MAP_W2_SEND_GET_MESSAGES_FOR_FOLDER,
MAP_W4_MESSAGES_IN_FOLDER,
MAP_W2_SEND_GET_MESSAGE_WITH_HANDLE,
MAP_W4_MESSAGE,
MAP_W2_SEND_DISCONNECT_REQUEST,
MAP_W4_DISCONNECT_RESPONSE,
} map_state_t;
@ -89,6 +98,13 @@ typedef struct map_client {
uint8_t incoming;
uint16_t goep_cid;
btstack_packet_handler_t client_handler;
const char * folder_name;
const char * current_folder;
uint16_t set_path_offset;
map_message_handle_t message_handle;
uint8_t get_message_attachment;
} map_client_t;
static map_client_t _map_client;
@ -126,9 +142,38 @@ static void map_client_emit_connection_closed_event(map_client_t * context){
context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
}
static void map_client_emit_operation_complete_event(map_client_t * context, uint8_t status){
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_MAP_META;
pos++; // skip len
event[pos++] = MAP_SUBEVENT_OPERATION_COMPLETED;
little_endian_store_16(event,pos,context->cid);
pos+=2;
event[pos++]= status;
event[1] = pos - 2;
if (pos != sizeof(event)) log_error("map_client_emit_can_send_now_event size %u", pos);
context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
}
static void map_message_handle_to_str(char * p, const map_message_handle_t msg_handle){
int i;
for (i = 0; i < MAP_MESSAGE_HANDLE_SIZE ; i++) {
uint8_t byte = msg_handle[i];
*p++ = char_for_nibble(byte >> 4);
*p++ = char_for_nibble(byte & 0x0F);
}
*p = 0;
}
static void map_handle_can_send_now(void){
uint8_t application_parameters[6];
int pos = 0;
char map_message_handle_to_str_buffer[MAP_MESSAGE_HANDLE_SIZE * 2 + 1];
uint8_t path_element[20];
uint16_t path_element_start;
uint16_t path_element_len;
int done;
switch (map_client->state){
case MAP_W2_SEND_CONNECT_REQUEST:
@ -136,7 +181,7 @@ static void map_handle_can_send_now(void){
goep_client_add_header_target(map_client->goep_cid, 16, map_client_access_service_uuid);
// Mandatory if the PSE advertises a PbapSupportedFeatures attribute in its SDP record, else excluded.
// if (goep_client_get_map_supported_features(map_client->goep_cid) != MAP_FEATURES_NOT_PRESENT){
application_parameters[0] = 0x29; // MAP_APPLICATION_PARAMETER_PBAP_SUPPORTED_FEATURES;
application_parameters[0] = 0x29; // MAP_APPLICATION_PARAMETER_MAP_SUPPORTED_FEATURES;
application_parameters[1] = 4;
big_endian_store_32(application_parameters, 2, map_supported_features);
goep_client_add_header_application_parameters(map_client->goep_cid, 6, &application_parameters[0]);
@ -145,17 +190,85 @@ static void map_handle_can_send_now(void){
map_client->state = MAP_W4_CONNECT_RESPONSE;
goep_client_execute(map_client->goep_cid);
break;
case MAP_W2_SEND_DISCONNECT_REQUEST:
goep_client_create_disconnect_request(map_client->goep_cid);
map_client->state = MAP_W4_DISCONNECT_RESPONSE;
goep_client_execute(map_client->goep_cid);
break;
case MAP_W2_SET_PATH_ROOT:
goep_client_create_set_path_request(map_client->goep_cid, 1 << 1); // Dont create directory
goep_client_add_header_name(map_client->goep_cid, "");
// state
map_client->state = MAP_W4_SET_PATH_ROOT_COMPLETE;
// send packet
goep_client_execute(map_client->goep_cid);
break;
case MAP_W2_SET_PATH_ELEMENT:
// find '/' or '\0'
path_element_start = map_client->set_path_offset;
while (map_client->current_folder[map_client->set_path_offset] != '\0' &&
map_client->current_folder[map_client->set_path_offset] != '/'){
map_client->set_path_offset++;
}
path_element_len = map_client->set_path_offset-path_element_start;
memcpy(path_element, &map_client->current_folder[path_element_start], path_element_len);
path_element[path_element_len] = 0;
// skip /
if (map_client->current_folder[map_client->set_path_offset] == '/'){
map_client->set_path_offset++;
}
// done?
done = map_client->current_folder[map_client->set_path_offset] == '\0';
// status
log_info("Path element '%s', done %u", path_element, done);
goep_client_create_set_path_request(map_client->goep_cid, 1 << 1); // Dont create directory
goep_client_add_header_name(map_client->goep_cid, (const char *) path_element); // next element
// state
map_client->state = MAP_W4_SET_PATH_ELEMENT_COMPLETE;
// send packet
goep_client_execute(map_client->goep_cid);
break;
case MAP_W2_SEND_GET_FOLDERS:
goep_client_create_get_request(map_client->goep_cid);
goep_client_add_header_type(map_client->goep_cid, "x-obex/folder-listing");
map_client->state = MAP_W4_FOLDERS;
goep_client_execute(map_client->goep_cid);
break;
case MAP_W2_SEND_GET_MESSAGES_FOR_FOLDER:
goep_client_create_get_request(map_client->goep_cid);
goep_client_add_header_type(map_client->goep_cid, "x-bt/MAP-msg-listing");
goep_client_add_header_name(map_client->goep_cid, map_client->folder_name);
map_client->state = MAP_W4_MESSAGES_IN_FOLDER;
goep_client_execute(map_client->goep_cid);
break;
case MAP_W2_SEND_GET_MESSAGE_WITH_HANDLE:
goep_client_create_get_request(map_client->goep_cid);
map_message_handle_to_str(map_message_handle_to_str_buffer, map_client->message_handle);
goep_client_add_header_name(map_client->goep_cid, map_message_handle_to_str_buffer);
goep_client_add_header_type(map_client->goep_cid, "x-bt/message");
application_parameters[pos++] = 0x0A; // attachment
application_parameters[pos++] = 1;
application_parameters[pos++] = map_client->get_message_attachment;
application_parameters[pos++] = 0x14; // Charset
application_parameters[pos++] = 1;
application_parameters[pos++] = 1; // UTF-8
map_client->state = MAP_W4_MESSAGE;
goep_client_execute(map_client->goep_cid);
break;
default:
break;
}
@ -164,7 +277,7 @@ static void map_handle_can_send_now(void){
static void map_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
printf("packet_type 0x%02x, event type 0x%02x, subevent 0x%02x\n", packet_type, hci_event_packet_get_type(packet), hci_event_goep_meta_get_subevent_code(packet));
// printf("packet_type 0x%02x, event type 0x%02x, subevent 0x%02x\n", packet_type, hci_event_packet_get_type(packet), hci_event_goep_meta_get_subevent_code(packet));
obex_iterator_t it;
uint8_t status;
// int i;
@ -232,12 +345,46 @@ static void map_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
map_client->state = MAP_INIT;
goep_client_disconnect(map_client->goep_cid);
break;
case MAP_W4_SET_PATH_ROOT_COMPLETE:
case MAP_W4_SET_PATH_ELEMENT_COMPLETE:
if (packet[0] == OBEX_RESP_SUCCESS){
// more path?
if (map_client->current_folder[map_client->set_path_offset]){
map_client->state = MAP_W2_SET_PATH_ELEMENT;
goep_client_request_can_send_now(map_client->goep_cid);
} else {
map_client->current_folder = NULL;
map_client->state = MAP_CONNECTED;
map_client_emit_operation_complete_event(map_client, 0);
}
} else if (packet[0] == OBEX_RESP_NOT_FOUND){
map_client->state = MAP_CONNECTED;
map_client_emit_operation_complete_event(map_client, OBEX_NOT_FOUND);
} else {
map_client->state = MAP_CONNECTED;
map_client_emit_operation_complete_event(map_client, OBEX_UNKNOWN_ERROR);
}
break;
case MAP_W4_FOLDERS:
map_client->state = MAP_CONNECTED;
printf("Folders:\n");
printf_hexdump(packet, size);
printf("\n");
break;
case MAP_W4_MESSAGES_IN_FOLDER:
map_client->state = MAP_CONNECTED;
printf("Messages:\n");
printf_hexdump(packet, size);
printf("\n");
break;
case MAP_W4_MESSAGE:
map_client->state = MAP_CONNECTED;
printf("Message :\n");
printf_hexdump(packet, size);
printf("\n");
break;
default:
break;
}
@ -265,18 +412,47 @@ uint8_t map_client_connect(btstack_packet_handler_t handler, bd_addr_t addr, uin
return 0;
}
uint8_t map_client_disconnect(uint16_t bip_cid){
UNUSED(bip_cid);
uint8_t map_client_disconnect(uint16_t map_cid){
UNUSED(map_cid);
if (map_client->state != MAP_CONNECTED) return BTSTACK_BUSY;
map_client->state = MAP_W2_SEND_DISCONNECT_REQUEST;
goep_client_request_can_send_now(map_client->goep_cid);
return 0;
}
uint8_t map_client_get_folder_listing(uint16_t bip_cid){
UNUSED(bip_cid);
uint8_t map_client_get_folder_listing(uint16_t map_cid){
UNUSED(map_cid);
if (map_client->state != MAP_CONNECTED) return BTSTACK_BUSY;
map_client->state = MAP_W2_SEND_GET_FOLDERS;
goep_client_request_can_send_now(map_client->goep_cid);
return 0;
}
uint8_t map_client_get_message_listing_for_folder(uint16_t map_cid, const char * folder_name){
UNUSED(map_cid);
if (map_client->state != MAP_CONNECTED) return BTSTACK_BUSY;
map_client->state = MAP_W2_SEND_GET_MESSAGES_FOR_FOLDER;
map_client->folder_name = folder_name;
goep_client_request_can_send_now(map_client->goep_cid);
return 0;
}
uint8_t map_client_get_message_with_handle(uint16_t map_cid, const map_message_handle_t message_handle, uint8_t with_attachment){
UNUSED(map_cid);
if (map_client->state != MAP_CONNECTED) return BTSTACK_BUSY;
map_client->state = MAP_W2_SEND_GET_MESSAGE_WITH_HANDLE;
memcpy(map_client->message_handle, message_handle, MAP_MESSAGE_HANDLE_SIZE);
map_client->get_message_attachment = with_attachment;
goep_client_request_can_send_now(map_client->goep_cid);
return 0;
}
uint8_t map_client_set_path(uint16_t map_cid, char * path){
UNUSED(map_cid);
if (map_client->state != MAP_CONNECTED) return BTSTACK_BUSY;
map_client->state = MAP_W2_SET_PATH_ROOT;
map_client->current_folder = path;
map_client->set_path_offset = 0;
goep_client_request_can_send_now(map_client->goep_cid);
return 0;
}

View File

@ -46,6 +46,12 @@ extern "C" {
/* API_START */
#define MAP_MESSAGE_HANDLE_SIZE 8
/**
* @brief MAP Message handle
*/
typedef uint8_t map_message_handle_t[MAP_MESSAGE_HANDLE_SIZE];
/**
*
*/
@ -65,14 +71,38 @@ uint8_t map_client_connect(btstack_packet_handler_t handler, bd_addr_t addr, uin
* @param map_cid
* @return status
*/
uint8_t map_client_disconnect(uint16_t bip_cid);
uint8_t map_client_disconnect(uint16_t map_cid);
/**
* @brief Get all folders.
* @brief Get list of folders.
* @param map_cid
* @return status
*/
uint8_t map_client_get_folder_listing(uint16_t bip_cid);
uint8_t map_client_get_folder_listing(uint16_t map_cid);
/**
* @brief Set current folder
* @param map_cid
* @return status
*/
uint8_t map_client_set_path(uint16_t map_cid, char * path);
/**
* @brief Get list of messages for particular folder.
* @param map_cid
* @param folder_name
* @return status
*/
uint8_t map_client_get_message_listing_for_folder(uint16_t map_cid, const char * folder_name);
/**
* @brief Get message with particular handle.
* @param map_cid
* @param map_message_handle
* @param with_attachment
* @return status
*/
uint8_t map_client_get_message_with_handle(uint16_t map_cid, const map_message_handle_t map_message_handle, uint8_t with_attachment);
/* API_END */

View File

@ -75,6 +75,9 @@ static bd_addr_t remote_addr;
// iPhone 5 static char * remote_addr_string = "6C:72:E7:10:22:EE";
// Android
static char * remote_addr_string = "a0:28:ed:04:33:b0";
static const char * folder_name = "telecom";
static map_message_handle_t message_handle;
static char * path = "telecom/msg";
static btstack_packet_callback_registration_t hci_event_callback_registration;
static uint16_t map_cid;
@ -89,7 +92,10 @@ static void show_usage(void){
printf("\n");
printf("a - establish MAP connection to %s\n", bd_addr_to_str(remote_addr));
printf("A - disconnect from %s\n", bd_addr_to_str(remote_addr));
printf("p - set path \'%s\'\n", path);
printf("f - get folder listing\n");
printf("F - get message listing for folder \'%s\'\n", folder_name);
printf("l - get message for last found handle'\n");
printf("\n");
}
@ -104,10 +110,22 @@ static void stdin_process(char c){
map_client_disconnect(map_cid);
break;
case 'p':
printf("[+] Get folder listing\n");
map_client_set_path(map_cid, path);
break;
case 'f':
printf("[+] Get folder listing from %s...\n", bd_addr_to_str(remote_addr));
printf("[+] Get folder listing\n");
map_client_get_folder_listing(map_cid);
break;
case 'F':
printf("[+] Get message listing for folder \'%s\'\n", folder_name);
map_client_get_message_listing_for_folder(map_cid, folder_name);
break;
case 'l':
printf("[+] Get message for last found handle\n");
map_client_get_message_with_handle(map_cid, message_handle, 1);
break;
default:
show_usage();