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 * @brief Provide password for OBEX Authentication after receiving PBAP_SUBEVENT_AUTHENTICATION_REQUEST. 238 * The status of PBAP connection establishment is reported via PBAP_SUBEVENT_CONNECTION_OPENED event, 239 * i.e. on success status field is set to ERROR_CODE_SUCCESS. 240 * 241 * @param pbap_cid 242 * @param password (null terminated string) - not copied, needs to stay valid until connection completed 243 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 244 */ 245 uint8_t pbap_authentication_password(uint16_t pbap_cid, const char * password); 246 247 /** 248 * @brief Disconnects PBAP connection with given identifier. 249 * Event PBAP_SUBEVENT_CONNECTION_CLOSED indicates that PBAP connection is closed. 250 * 251 * @param pbap_cid 252 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 253 */ 254 uint8_t pbap_disconnect(uint16_t pbap_cid); 255 256 /** 257 * @brief Set current folder on PSE. The status is reported via PBAP_SUBEVENT_OPERATION_COMPLETED event. 258 * 259 * @param pbap_cid 260 * @param path - note: path is not copied 261 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 262 */ 263 uint8_t pbap_set_phonebook(uint16_t pbap_cid, const char * path); 264 265 /** 266 * @brief Set vCard Selector for get/pull phonebook. No event is emitted. 267 * 268 * @param pbap_cid 269 * @param vcard_selector - combination of PBAP_PROPERTY_MASK_* properties 270 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 271 */ 272 uint8_t pbap_set_vcard_selector(uint16_t pbap_cid, uint32_t vcard_selector); 273 274 /** 275 * @brief Set vCard Selector for get/pull phonebook. No event is emitted. 276 * 277 * @param pbap_cid 278 * @param vcard_selector_operator - PBAP_VCARD_SELECTOR_OPERATOR_OR (default) or PBAP_VCARD_SELECTOR_OPERATOR_AND 279 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 280 */ 281 uint8_t pbap_set_vcard_selector_operator(uint16_t pbap_cid, int vcard_selector_operator); 282 283 /** 284 * @brief Set Property Selector. No event is emitted. 285 * @param pbap_cid 286 * @param property_selector - combination of PBAP_PROPERTY_MASK_* properties 287 * @return 288 */ 289 uint8_t pbap_set_property_selector(uint16_t pbap_cid, uint32_t property_selector); 290 291 /** 292 * @brief Set number of items returned by pull phonebook. 293 * @param pbap_cid 294 * @param max_list_count 295 * @return 296 */ 297 uint8_t pbap_set_max_list_count(uint16_t pbap_cid, uint16_t max_list_count); 298 299 /** 300 * @bbrief Set start offset for pull phonebook 301 * @param pbap_cid 302 * @param list_start_offset 303 * @return 304 */ 305 uint8_t pbap_set_list_start_offset(uint16_t pbap_cid, uint16_t list_start_offset); 306 307 /** 308 * @bbrief Set order for pbap_pull_vcard_listing 309 * @param pbap_cid 310 * @param order 311 * @return 312 */ 313 uint8_t pbap_set_order(uint16_t pbap_cid, uint8_t order); 314 315 /** 316 * @bbrief Set search property for pbap_pull_vcard_listing 317 * @param pbap_cid 318 * @param search_property 319 * @return 320 */ 321 uint8_t pbap_set_search_property(uint16_t pbap_cid, uint8_t search_property); 322 323 /** 324 * @bbrief Set search property for pbap_pull_vcard_listing 325 * @param pbap_cid 326 * @param search_value 327 * @return 328 */ 329 uint8_t pbap_set_search_value(uint16_t pbap_cid, const char * search_value); 330 331 /** 332 * @brief Get size of phone book from PSE. The result is reported via PBAP_SUBEVENT_PHONEBOOK_SIZE event. 333 * 334 * @param pbap_cid 335 * @param path - note: path is not copied, common path 'telecom/pb.vcf' 336 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 337 */ 338 uint8_t pbap_get_phonebook_size(uint16_t pbap_cid, const char * path); 339 340 /** 341 * @brief Pull phone book from PSE. The result is reported via registered packet handler (see pbap_connect function), 342 * with packet type set to PBAP_DATA_PACKET. Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the phone book. 343 * 344 * @param pbap_cid 345 * @param path - note: path is not copied, common path 'telecom/pb.vcf' 346 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 347 */ 348 uint8_t pbap_pull_phonebook(uint16_t pbap_cid, const char * path); 349 350 /** 351 * @brief Pull vCard listing. vCard data is emitted via PBAP_SUBEVENT_CARD_RESULT event. 352 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of vCard listing. 353 * 354 * @param pbap_cid 355 * @param path 356 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 357 */ 358 uint8_t pbap_pull_vcard_listing(uint16_t pbap_cid, const char * path); 359 360 /** 361 * @brief Pull vCard entry. The result is reported via callback (see pbap_connect function), 362 * with packet type set to PBAP_DATA_PACKET. 363 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the vCard entry. 364 * 365 * @param pbap_cid 366 * @param path 367 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 368 */ 369 uint8_t pbap_pull_vcard_entry(uint16_t pbap_cid, const char * path); 370 371 /** 372 * @brief Lookup contact(s) by phone number. vCard data is emitted via PBAP_SUBEVENT_CARD_RESULT event. 373 * Event PBAP_SUBEVENT_OPERATION_COMPLETED marks the end of the lookup. 374 * 375 * @param pbap_cid 376 * @param phone_number 377 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 378 */ 379 uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number); 380 381 /** 382 * @brief Abort current operation. No event is emitted. 383 * 384 * @param pbap_cid 385 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 386 */ 387 uint8_t pbap_abort(uint16_t pbap_cid); 388 389 390 /** 391 * @brief Set flow control mode - default is off. No event is emitted. 392 * @note When enabled, pbap_next_packet needs to be called after a packet was processed to receive the next one 393 * 394 * @param pbap_cid 395 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 396 */ 397 uint8_t pbap_set_flow_control_mode(uint16_t pbap_cid, int enable); 398 399 /** 400 * @brief Trigger next packet from PSE when Flow Control Mode is enabled. 401 * @param pbap_cid 402 * @return status ERROR_CODE_SUCCESS on success, otherwise BTSTACK_BUSY if in a wrong state. 403 */ 404 uint8_t pbap_next_packet(uint16_t pbap_cid); 405 406 /** 407 * @brief De-Init PBAP Client 408 */ 409 void pbap_client_deinit(void); 410 411 /* API_END */ 412 413 #if defined __cplusplus 414 } 415 #endif 416 #endif 417