1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 /** 39 * @title PBAP Client 40 * 41 */ 42 43 #ifndef PBAP_CLIENT_H 44 #define PBAP_CLIENT_H 45 46 #if defined __cplusplus 47 extern "C" { 48 #endif 49 50 #include <stdint.h> 51 52 #include "btstack_config.h" 53 #include "yxml.h" 54 #include "classic/obex_srm_client.h" 55 #include "classic/obex_parser.h" 56 57 // max len of phone number used for lookup in pbap_lookup_by_number 58 #define PBAP_MAX_PHONE_NUMBER_LEN 32 59 60 // max len of name reported in PBAP_SUBEVENT_CARD_RESULT 61 #define PBAP_MAX_NAME_LEN 32 62 // max len of vcard handle reported in PBAP_SUBEVENT_CARD_RESULT 63 #define PBAP_MAX_HANDLE_LEN 16 64 65 66 typedef enum { 67 PBAP_CLIENT_INIT = 0, 68 PBAP_CLIENT_W4_GOEP_CONNECTION, 69 PBAP_CLIENT_W2_SEND_CONNECT_REQUEST, 70 PBAP_CLIENT_W4_CONNECT_RESPONSE, 71 PBAP_CLIENT_W4_USER_AUTHENTICATION, 72 PBAP_CLIENT_W2_SEND_AUTHENTICATED_CONNECT, 73 PBAP_CLIENT_CONNECTED, 74 // 75 PBAP_CLIENT_W2_SEND_DISCONNECT_REQUEST, 76 PBAP_CLIENT_W4_DISCONNECT_RESPONSE, 77 // 78 PBAP_CLIENT_W2_PULL_PHONEBOOK, 79 PBAP_CLIENT_W4_PHONEBOOK, 80 PBAP_CLIENT_W2_SET_PATH_ROOT, 81 PBAP_CLIENT_W4_SET_PATH_ROOT_COMPLETE, 82 PBAP_CLIENT_W2_SET_PATH_ELEMENT, 83 PBAP_CLIENT_W4_SET_PATH_ELEMENT_COMPLETE, 84 PBAP_CLIENT_W2_GET_PHONEBOOK_SIZE, 85 PBAP_CLIENT_W4_GET_PHONEBOOK_SIZE_COMPLETE, 86 // - pull vacard liast 87 PBAP_CLIENT_W2_GET_CARD_LIST, 88 PBAP_CLIENT_W4_GET_CARD_LIST_COMPLETE, 89 // - pull vcard entry 90 PBAP_CLIENT_W2_GET_CARD_ENTRY, 91 PBAP_CLIENT_W4_GET_CARD_ENTRY_COMPLETE, 92 // abort operation 93 PBAP_CLIENT_W4_ABORT_COMPLETE, 94 95 } pbap_client_state_t; 96 97 typedef enum { 98 PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_TYPE = 0, 99 PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_LEN, 100 PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_VALUE, 101 PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_INVALID, 102 } pbap_client_phonebook_size_parser_state_t; 103 104 typedef struct { 105 // parsing 106 pbap_client_phonebook_size_parser_state_t state; 107 uint8_t type; 108 uint8_t len; 109 uint8_t pos; 110 // data 111 bool have_size; 112 uint8_t size_buffer[2]; 113 } pbap_client_phonebook_size_parser_t; 114 115 typedef enum { 116 OBEX_AUTH_PARSER_STATE_W4_TYPE = 0, 117 OBEX_AUTH_PARSER_STATE_W4_LEN, 118 OBEX_AUTH_PARSER_STATE_W4_VALUE, 119 OBEX_AUTH_PARSER_STATE_INVALID, 120 } pbap_client_obex_auth_parser_state_t; 121 122 typedef struct { 123 // parsing 124 pbap_client_obex_auth_parser_state_t state; 125 uint8_t type; 126 uint8_t len; 127 uint8_t pos; 128 // data 129 uint8_t authentication_options; 130 uint16_t authentication_nonce[16]; 131 } pbap_client_obex_auth_parser_t; 132 133 typedef struct pbap_client { 134 // pbap client linked list 135 btstack_linked_item_t item; 136 137 // goep client linked list 138 goep_client_t goep_client; 139 140 pbap_client_state_t state; 141 bd_addr_t bd_addr; 142 hci_con_handle_t con_handle; 143 uint16_t goep_cid; 144 btstack_packet_handler_t client_handler; 145 int request_number; 146 const char * current_folder; 147 const char * phone_number; 148 const char * phonebook_path; 149 const char * vcard_name; 150 uint16_t set_path_offset; 151 /* vcard selector / operator */ 152 uint32_t vcard_selector; 153 uint8_t vcard_selector_operator; 154 uint8_t vcard_selector_supported; 155 /* property selector */ 156 uint32_t property_selector; 157 uint16_t list_start_offset; 158 uint16_t max_list_count; 159 uint8_t order; 160 uint8_t search_property; 161 const char * search_value; 162 /* abort */ 163 uint8_t abort_operation; 164 /* obex parser */ 165 bool obex_parser_waiting_for_response; 166 obex_parser_t obex_parser; 167 uint8_t obex_header_buffer[4]; 168 /* authentication */ 169 pbap_client_obex_auth_parser_t obex_auth_parser; 170 const char * authentication_password; 171 /* xml parser */ 172 yxml_t xml_parser; 173 uint8_t xml_buffer[50]; 174 /* vcard listing parser */ 175 bool parser_card_found; 176 bool parser_name_found; 177 bool parser_handle_found; 178 char parser_name[PBAP_MAX_NAME_LEN]; 179 char parser_handle[PBAP_MAX_HANDLE_LEN]; 180 /* phonebook size */ 181 pbap_client_phonebook_size_parser_t phonebook_size_parser; 182 /* flow control mode */ 183 uint8_t flow_control_enabled; 184 uint8_t flow_next_triggered; 185 bool flow_wait_for_user; 186 /* srm */ 187 obex_srm_client_t obex_srm; 188 } pbap_client_t; 189 190 /* API_START */ 191 192 /** 193 * Setup PhoneBook Access Client 194 */ 195 void pbap_client_init(void); 196 197 /** 198 * @brief Create PBAP connection to a Phone Book Server (PSE) server on a remote device. 199 * If the server requires authentication, a PBAP_SUBEVENT_AUTHENTICATION_REQUEST is emitted, which 200 * can be answered with pbap_authentication_password(..). 201 * The status of PBAP connection establishment is reported via PBAP_SUBEVENT_CONNECTION_OPENED event, 202 * i.e. on success status field is set to ERROR_CODE_SUCCESS. 203 * 204 * This function allows for multiple parallel connections. 205 * 206 * @param client storage for connection state. Must stay valid until connection closes 207 * @param l2cap_ertm_config 208 * @param l2cap_ertm_buffer_size 209 * @param l2cap_ertm_buffer 210 * @param handler 211 * @param addr 212 * @param out_cid to use for further commands 213 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_MEMORY_ALLOC_FAILED if PBAP or GOEP connection already exists. 214 */ 215 216 uint8_t pbap_client_connect(pbap_client_t * client, l2cap_ertm_config_t *l2cap_ertm_config, uint8_t *l2cap_ertm_buffer, 217 uint16_t l2cap_ertm_buffer_size, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t * out_cid); 218 219 /** 220 * @brief Create PBAP connection to a Phone Book Server (PSE) server on a remote device. 221 * If the server requires authentication, a PBAP_SUBEVENT_AUTHENTICATION_REQUEST is emitted, which 222 * can be answered with pbap_authentication_password(..). 223 * The status of PBAP connection establishment is reported via PBAP_SUBEVENT_CONNECTION_OPENED event, 224 * i.e. on success status field is set to ERROR_CODE_SUCCESS. 225 * 226 * This function uses a single pbap_client_t and l2cap ertm buffer instance and can only be used for a single connection. 227 * Fur multiple parallel connections, use pbap_client_connect. 228 * 229 * @param handler 230 * @param addr 231 * @param out_cid to use for further commands 232 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_MEMORY_ALLOC_FAILED if PBAP or GOEP connection already exists. 233 */ 234 uint8_t pbap_connect(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t * out_cid); 235 236 /** 237 * Create SDP Record for Phonebook Access Client 238 * @param service 239 * @param service_record_handle 240 * @param service_name 241 */ 242 void pbap_client_create_sdp_record(uint8_t *service, uint32_t service_record_handle, const char *service_name); 243 244 /** 245 * @brief Provide password for OBEX Authentication after receiving PBAP_SUBEVENT_AUTHENTICATION_REQUEST. 246 * The status of PBAP connection establishment is reported via PBAP_SUBEVENT_CONNECTION_OPENED event, 247 * i.e. on success status field is set to ERROR_CODE_SUCCESS. 248 * 249 * @param pbap_cid 250 * @param password (null terminated string) - not copied, needs to stay valid until connection completed 251 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 252 */ 253 uint8_t pbap_authentication_password(uint16_t pbap_cid, const char * password); 254 255 /** 256 * @brief Disconnects PBAP connection with given identifier. 257 * Event PBAP_SUBEVENT_CONNECTION_CLOSED indicates that PBAP connection is closed. 258 * 259 * @param pbap_cid 260 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 261 */ 262 uint8_t pbap_disconnect(uint16_t pbap_cid); 263 264 /** 265 * @brief Set current folder on PSE. The status is reported via PBAP_SUBEVENT_OPERATION_COMPLETED event. 266 * 267 * @param pbap_cid 268 * @param path - note: path is not copied 269 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 270 */ 271 uint8_t pbap_set_phonebook(uint16_t pbap_cid, const char * path); 272 273 /** 274 * @brief Set vCard Selector for get/pull phonebook. No event is emitted. 275 * 276 * @param pbap_cid 277 * @param vcard_selector - combination of PBAP_PROPERTY_MASK_* properties 278 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 279 */ 280 uint8_t pbap_set_vcard_selector(uint16_t pbap_cid, uint32_t vcard_selector); 281 282 /** 283 * @brief Set vCard Selector for get/pull phonebook. No event is emitted. 284 * 285 * @param pbap_cid 286 * @param vcard_selector_operator - PBAP_VCARD_SELECTOR_OPERATOR_OR (default) or PBAP_VCARD_SELECTOR_OPERATOR_AND 287 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 288 */ 289 uint8_t pbap_set_vcard_selector_operator(uint16_t pbap_cid, int vcard_selector_operator); 290 291 /** 292 * @brief Set Property Selector. No event is emitted. 293 * @param pbap_cid 294 * @param property_selector - combination of PBAP_PROPERTY_MASK_* properties 295 * @return 296 */ 297 uint8_t pbap_set_property_selector(uint16_t pbap_cid, uint32_t property_selector); 298 299 /** 300 * @brief Set number of items returned by pull phonebook. 301 * @param pbap_cid 302 * @param max_list_count 303 * @return 304 */ 305 uint8_t pbap_set_max_list_count(uint16_t pbap_cid, uint16_t max_list_count); 306 307 /** 308 * @bbrief Set start offset for pull phonebook 309 * @param pbap_cid 310 * @param list_start_offset 311 * @return 312 */ 313 uint8_t pbap_set_list_start_offset(uint16_t pbap_cid, uint16_t list_start_offset); 314 315 /** 316 * @bbrief Set order for pbap_pull_vcard_listing 317 * @param pbap_cid 318 * @param order 319 * @return 320 */ 321 uint8_t pbap_set_order(uint16_t pbap_cid, uint8_t order); 322 323 /** 324 * @bbrief Set search property for pbap_pull_vcard_listing 325 * @param pbap_cid 326 * @param search_property 327 * @return 328 */ 329 uint8_t pbap_set_search_property(uint16_t pbap_cid, uint8_t search_property); 330 331 /** 332 * @bbrief Set search property for pbap_pull_vcard_listing 333 * @param pbap_cid 334 * @param search_value 335 * @return 336 */ 337 uint8_t pbap_set_search_value(uint16_t pbap_cid, const char * search_value); 338 339 /** 340 * @brief Get size of phone book from PSE. The result is reported via PBAP_SUBEVENT_PHONEBOOK_SIZE event. 341 * 342 * @param pbap_cid 343 * @param path - note: path is not copied, common path 'telecom/pb.vcf' 344 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 345 */ 346 uint8_t pbap_get_phonebook_size(uint16_t pbap_cid, const char * path); 347 348 /** 349 * @brief Pull phone book from PSE. The result is reported via registered packet handler (see pbap_connect function), 350 * with packet type set to PBAP_DATA_PACKET. Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the phone book. 351 * 352 * @param pbap_cid 353 * @param path - note: path is not copied, common path 'telecom/pb.vcf' 354 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 355 */ 356 uint8_t pbap_pull_phonebook(uint16_t pbap_cid, const char * path); 357 358 /** 359 * @brief Pull vCard listing. vCard data is emitted via PBAP_SUBEVENT_CARD_RESULT event. 360 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of vCard listing. 361 * 362 * @param pbap_cid 363 * @param path 364 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 365 */ 366 uint8_t pbap_pull_vcard_listing(uint16_t pbap_cid, const char * path); 367 368 /** 369 * @brief Pull vCard entry. The result is reported via callback (see pbap_connect function), 370 * with packet type set to PBAP_DATA_PACKET. 371 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the vCard entry. 372 * 373 * @param pbap_cid 374 * @param path 375 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 376 */ 377 uint8_t pbap_pull_vcard_entry(uint16_t pbap_cid, const char * path); 378 379 /** 380 * @brief Lookup contact(s) by phone number. vCard data is emitted via PBAP_SUBEVENT_CARD_RESULT event. 381 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the lookup. 382 * 383 * @param pbap_cid 384 * @param phone_number 385 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 386 */ 387 uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number); 388 389 /** 390 * @brief Abort current operation. No event is emitted. 391 * 392 * @param pbap_cid 393 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 394 */ 395 uint8_t pbap_abort(uint16_t pbap_cid); 396 397 398 /** 399 * @brief Set flow control mode - default is off. No event is emitted. 400 * @note When enabled, pbap_next_packet needs to be called after a packet was processed to receive the next one 401 * 402 * @param pbap_cid 403 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 404 */ 405 uint8_t pbap_set_flow_control_mode(uint16_t pbap_cid, int enable); 406 407 /** 408 * @brief Trigger next packet from PSE when Flow Control Mode is enabled. 409 * @param pbap_cid 410 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 411 */ 412 uint8_t pbap_next_packet(uint16_t pbap_cid); 413 414 /** 415 * @brief De-Init PBAP Client 416 */ 417 void pbap_client_deinit(void); 418 419 /* API_END */ 420 421 #if defined __cplusplus 422 } 423 #endif 424 #endif 425