xref: /btstack/src/classic/pbap_client.c (revision 8bb555aa6b09e3f91bb7caaba1c7b6db6ac22e10)
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 #define BTSTACK_FILE__ "pbap_client.c"
39 
40 #include "btstack_config.h"
41 
42 #include <stdint.h>
43 #include <string.h>
44 
45 #include "hci_cmd.h"
46 #include "btstack_run_loop.h"
47 #include "btstack_debug.h"
48 #include "hci.h"
49 #include "btstack_memory.h"
50 #include "hci_dump.h"
51 #include "l2cap.h"
52 #include "bluetooth_sdp.h"
53 #include "classic/sdp_client_rfcomm.h"
54 #include "btstack_event.h"
55 #include "md5.h"
56 #include "yxml.h"
57 
58 #include "classic/obex.h"
59 #include "classic/obex_parser.h"
60 #include "classic/goep_client.h"
61 #include "classic/pbap_client.h"
62 
63 // 796135f0-f0c5-11d8-0966- 0800200c9a66
64 static const uint8_t pbap_uuid[] = { 0x79, 0x61, 0x35, 0xf0, 0xf0, 0xc5, 0x11, 0xd8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66};
65 
66 const char * pbap_phonebook_type     = "x-bt/phonebook";
67 const char * pbap_vcard_listing_type = "x-bt/vcard-listing";
68 const char * pbap_vcard_entry_type   = "x-bt/vcard";
69 
70 const char * pbap_vcard_listing_name = "pb";
71 
72 typedef enum {
73     PBAP_INIT = 0,
74     PBAP_W4_GOEP_CONNECTION,
75     PBAP_W2_SEND_CONNECT_REQUEST,
76     PBAP_W4_CONNECT_RESPONSE,
77     PBAP_W4_USER_AUTHENTICATION,
78     PBAP_W2_SEND_AUTHENTICATED_CONNECT,
79     PBAP_CONNECT_RESPONSE_RECEIVED,
80     PBAP_CONNECTED,
81     //
82     PBAP_W2_SEND_DISCONNECT_REQUEST,
83     PBAP_W4_DISCONNECT_RESPONSE,
84     //
85     PBAP_W2_PULL_PHONEBOOK,
86     PBAP_W4_PHONEBOOK,
87     PBAP_W2_SET_PATH_ROOT,
88     PBAP_W4_SET_PATH_ROOT_COMPLETE,
89     PBAP_W2_SET_PATH_ELEMENT,
90     PBAP_W4_SET_PATH_ELEMENT_COMPLETE,
91     PBAP_W2_GET_PHONEBOOK_SIZE,
92     PBAP_W4_GET_PHONEBOOK_SIZE_COMPLETE,
93     // - pull vacard liast
94     PBAP_W2_GET_CARD_LIST,
95     PBAP_W4_GET_CARD_LIST_COMPLETE,
96     // - pull vcard entry
97     PBAP_W2_GET_CARD_ENTRY,
98     PBAP_W4_GET_CARD_ENTRY_COMPLETE,
99     // abort operation
100     PBAP_W4_ABORT_COMPLETE,
101 
102 } pbap_state_t;
103 
104 typedef enum {
105     SRM_DISABLED,
106     SRM_W4_CONFIRM,
107     SRM_ENABLED_BUT_WAITING,
108     SRM_ENABLED
109 } srm_state_t;
110 
111 typedef enum {
112     OBEX_AUTH_PARSER_STATE_W4_TYPE = 0,
113     OBEX_AUTH_PARSER_STATE_W4_LEN,
114     OBEX_AUTH_PARSER_STATE_W4_VALUE,
115     OBEX_AUTH_PARSER_STATE_INVALID,
116 } obex_auth_parser_state_t;
117 
118 typedef struct {
119     // parsing
120     obex_auth_parser_state_t state;
121     uint8_t type;
122     uint8_t len;
123     uint8_t pos;
124     // data
125     uint8_t  authentication_options;
126     uint16_t authentication_nonce[16];
127 } obex_auth_parser_t;
128 
129 typedef struct {
130     uint8_t srm_value;
131     uint8_t srmp_value;
132 } obex_srm_t;
133 
134 typedef enum {
135     PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_TYPE = 0,
136     PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_LEN,
137     PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_VALUE,
138     PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_INVALID,
139 } pbap_client_phonebook_size_parser_state_t;
140 
141 typedef struct {
142     // parsing
143     pbap_client_phonebook_size_parser_state_t state;
144     uint8_t type;
145     uint8_t len;
146     uint8_t pos;
147     // data
148     bool have_size;
149     uint8_t  size_buffer[2];
150 } pbap_client_phonebook_size_parser_t;
151 
152 typedef struct pbap_client {
153     pbap_state_t state;
154     uint16_t  cid;
155     bd_addr_t bd_addr;
156     hci_con_handle_t con_handle;
157     uint8_t   incoming;
158     uint16_t  goep_cid;
159     btstack_packet_handler_t client_handler;
160     int request_number;
161     const char * current_folder;
162     const char * phone_number;
163     const char * phonebook_path;
164     const char * vcard_name;
165     uint16_t set_path_offset;
166     /* vcard selector / operator */
167     uint32_t vcard_selector;
168     uint8_t  vcard_selector_operator;
169     uint8_t  vcard_selector_supported;
170     /* property selector */
171     uint32_t property_selector;
172     /* abort */
173     uint8_t  abort_operation;
174     /* obex parser */
175     bool obex_parser_waiting_for_response;
176     obex_parser_t obex_parser;
177     uint8_t obex_header_buffer[4];
178     /* authentication */
179     obex_auth_parser_t obex_auth_parser;
180     const char * authentication_password;
181     /* xml parser */
182     yxml_t  xml_parser;
183     uint8_t xml_buffer[50];
184     /* vcard listing parser */
185     bool parser_card_found;
186     bool parser_name_found;
187     bool parser_handle_found;
188     char parser_name[PBAP_MAX_NAME_LEN];
189     char parser_handle[PBAP_MAX_HANDLE_LEN];
190     /* phonebook size */
191     pbap_client_phonebook_size_parser_t phonebook_size_parser;
192     /* flow control mode */
193     uint8_t flow_control_enabled;
194     uint8_t flow_next_triggered;
195     bool flow_wait_for_user;
196     /* srm */
197     obex_srm_t obex_srm;
198     srm_state_t srm_state;
199 } pbap_client_t;
200 
201 static uint32_t pbap_client_supported_features;
202 
203 static pbap_client_t pbap_client_singleton;
204 static pbap_client_t * pbap_client = &pbap_client_singleton;
205 
206 static void pbap_client_emit_connected_event(pbap_client_t * context, uint8_t status){
207     uint8_t event[15];
208     int pos = 0;
209     event[pos++] = HCI_EVENT_PBAP_META;
210     pos++;  // skip len
211     event[pos++] = PBAP_SUBEVENT_CONNECTION_OPENED;
212     little_endian_store_16(event,pos,context->cid);
213     pos+=2;
214     event[pos++] = status;
215     (void)memcpy(&event[pos], context->bd_addr, 6);
216     pos += 6;
217     little_endian_store_16(event,pos,context->con_handle);
218     pos += 2;
219     event[pos++] = context->incoming;
220     event[1] = pos - 2;
221     if (pos != sizeof(event)) log_error("goep_client_emit_connected_event size %u", pos);
222     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
223 }
224 
225 static void pbap_client_emit_connection_closed_event(pbap_client_t * context){
226     uint8_t event[5];
227     int pos = 0;
228     event[pos++] = HCI_EVENT_PBAP_META;
229     pos++;  // skip len
230     event[pos++] = PBAP_SUBEVENT_CONNECTION_CLOSED;
231     little_endian_store_16(event,pos,context->cid);
232     pos+=2;
233     event[1] = pos - 2;
234     if (pos != sizeof(event)) log_error("pbap_client_emit_connection_closed_event size %u", pos);
235     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
236 }
237 
238 static void pbap_client_emit_operation_complete_event(pbap_client_t * context, uint8_t status){
239     uint8_t event[6];
240     int pos = 0;
241     event[pos++] = HCI_EVENT_PBAP_META;
242     pos++;  // skip len
243     event[pos++] = PBAP_SUBEVENT_OPERATION_COMPLETED;
244     little_endian_store_16(event,pos,context->cid);
245     pos+=2;
246     event[pos++]= status;
247     event[1] = pos - 2;
248     if (pos != sizeof(event)) log_error("pbap_client_emit_can_send_now_event size %u", pos);
249     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
250 }
251 
252 static void pbap_client_emit_phonebook_size_event(pbap_client_t * context, uint8_t status, uint16_t phonebook_size){
253     uint8_t event[8];
254     int pos = 0;
255     event[pos++] = HCI_EVENT_PBAP_META;
256     pos++;  // skip len
257     event[pos++] = PBAP_SUBEVENT_PHONEBOOK_SIZE;
258     little_endian_store_16(event,pos,context->cid);
259     pos+=2;
260     event[pos++] = status;
261     little_endian_store_16(event,pos, phonebook_size);
262     pos+=2;
263     event[1] = pos - 2;
264     if (pos != sizeof(event)) log_error("pbap_client_emit_phonebook_size_event size %u", pos);
265     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
266 }
267 
268 static void pbap_client_emit_authentication_event(pbap_client_t * context, uint8_t options){
269     // split options
270     uint8_t user_id_required = (options & 1) ? 1 : 0;
271     uint8_t full_access      = (options & 2) ? 1 : 0;
272 
273     uint8_t event[7];
274     int pos = 0;
275     event[pos++] = HCI_EVENT_PBAP_META;
276     pos++;  // skip len
277     event[pos++] = PBAP_SUBEVENT_AUTHENTICATION_REQUEST;
278     little_endian_store_16(event,pos,context->cid);
279     pos+=2;
280     event[pos++] = user_id_required;
281     event[pos++] = full_access;
282     if (pos != sizeof(event)) log_error("pbap_client_emit_authentication_event size %u", pos);
283     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
284 }
285 
286 static void pbap_client_emit_card_result_event(pbap_client_t * context, const char * name, const char * handle){
287     uint8_t event[5 + PBAP_MAX_NAME_LEN + PBAP_MAX_HANDLE_LEN];
288     int pos = 0;
289     event[pos++] = HCI_EVENT_PBAP_META;
290     pos++;  // skip len
291     event[pos++] = PBAP_SUBEVENT_CARD_RESULT;
292     little_endian_store_16(event,pos,context->cid);
293     pos+=2;
294     int name_len = btstack_min(PBAP_MAX_NAME_LEN, strlen(name));
295     event[pos++] = name_len;
296     (void)memcpy(&event[pos], name, name_len);
297     pos += name_len;
298     int handle_len = btstack_min(PBAP_MAX_HANDLE_LEN, strlen(handle));
299     event[pos++] = handle_len;
300     (void)memcpy(&event[pos], handle, handle_len);
301     pos += handle_len;
302     event[1] = pos - 2;
303     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
304 }
305 
306 static const uint8_t collon = (uint8_t) ':';
307 
308 static void pbap_client_vcard_listing_init_parser(pbap_client_t * client){
309     yxml_init(&client->xml_parser, client->xml_buffer, sizeof(client->xml_buffer));
310     client->parser_card_found = false;
311     client->parser_name_found = false;
312     client->parser_handle_found = false;
313 }
314 
315 static void pbap_client_phonebook_size_parser_init(pbap_client_phonebook_size_parser_t * phonebook_size_parer){
316     memset(phonebook_size_parer, 0, sizeof(pbap_client_phonebook_size_parser_t));
317 }
318 
319 static void pbap_client_phoneboook_size_parser_process_data(pbap_client_phonebook_size_parser_t * phonebook_size_parser, const uint8_t * data_buffer, uint16_t data_len){
320     while (data_len){
321         uint16_t bytes_to_consume = 1;
322         switch(phonebook_size_parser->state){
323             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_INVALID:
324                 return;
325             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_TYPE:
326                 phonebook_size_parser->type = *data_buffer;
327                 phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_LEN;
328                 break;
329             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_LEN:
330                 phonebook_size_parser->len = *data_buffer;
331                 phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_VALUE;
332                 switch (phonebook_size_parser->type){
333                     case PBAP_APPLICATION_PARAMETER_PHONEBOOK_SIZE:
334                         if (phonebook_size_parser->len != 2){
335                             phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_INVALID;
336                             return;
337                         }
338                         break;
339                     default:
340                         break;
341                     }
342                 break;
343             case PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_VALUE:
344                 bytes_to_consume = btstack_min(phonebook_size_parser->len - phonebook_size_parser->pos, data_len);
345                 switch (phonebook_size_parser->type){
346                     case PBAP_APPLICATION_PARAMETER_PHONEBOOK_SIZE:
347                         memcpy(&phonebook_size_parser->size_buffer[phonebook_size_parser->pos], data_buffer, bytes_to_consume);
348                         break;
349                     default:
350                         // ignore data
351                         break;
352                 }
353                 phonebook_size_parser->pos += bytes_to_consume;
354                 if (phonebook_size_parser->pos == phonebook_size_parser->len){
355                     phonebook_size_parser->state = PBAP_CLIENT_PHONEBOOK_SIZE_PARSER_STATE_W4_TYPE;
356                     switch (phonebook_size_parser->type){
357                         case PBAP_APPLICATION_PARAMETER_PHONEBOOK_SIZE:
358                             phonebook_size_parser->have_size = true;
359                             break;
360                         default:
361                             break;
362                     }
363                 }
364                 break;
365             default:
366                 break;
367         }
368         data_buffer += bytes_to_consume;
369         data_len    -= bytes_to_consume;
370     }
371 }
372 
373 static void obex_auth_parser_init(obex_auth_parser_t * auth_parser){
374     memset(auth_parser, 0, sizeof(obex_auth_parser_t));
375 }
376 
377 static void obex_auth_parser_process_data(obex_auth_parser_t * auth_parser, const uint8_t * data_buffer, uint16_t data_len){
378     while (data_len){
379         uint16_t bytes_to_consume = 1;
380         switch(auth_parser->state){
381             case OBEX_AUTH_PARSER_STATE_INVALID:
382                 return;
383             case OBEX_AUTH_PARSER_STATE_W4_TYPE:
384                 auth_parser->type = *data_buffer;
385                 auth_parser->state = OBEX_AUTH_PARSER_STATE_W4_LEN;
386                 break;
387             case OBEX_AUTH_PARSER_STATE_W4_LEN:
388                 auth_parser->len = *data_buffer;
389                 switch (auth_parser->type){
390                     case 0:
391                         if (auth_parser->len != 0x10){
392                             auth_parser->state = OBEX_AUTH_PARSER_STATE_INVALID;
393                             return;
394                         }
395                         break;
396                     case 1:
397                         if (auth_parser->len != 0x01){
398                             auth_parser->state = OBEX_AUTH_PARSER_STATE_INVALID;
399                             return;
400                         }
401                         break;
402                     case 2:
403                         // TODO: handle charset
404                         // charset_code = challenge_data[i];
405                         break;
406                     default:
407                         break;
408                 }
409                 auth_parser->state = OBEX_AUTH_PARSER_STATE_W4_VALUE;
410                 break;
411             case OBEX_AUTH_PARSER_STATE_W4_VALUE:
412                 bytes_to_consume = btstack_min(auth_parser->len - auth_parser->pos, data_len);
413                 switch (auth_parser->type){
414                     case 0:
415                         memcpy(&auth_parser->authentication_nonce[auth_parser->pos], data_buffer, bytes_to_consume);
416                         break;
417                     case 1:
418                         auth_parser->authentication_options = *data_buffer;
419                         break;
420                     default:
421                         // ignore
422                         break;
423                 }
424                 auth_parser->pos += bytes_to_consume;
425                 if (auth_parser->pos == auth_parser->len){
426                     auth_parser->state = OBEX_AUTH_PARSER_STATE_W4_TYPE;
427                 }
428                 break;
429             default:
430                 btstack_unreachable();
431                 break;
432         }
433         data_buffer += bytes_to_consume;
434         data_len    -= bytes_to_consume;
435     }
436 }
437 
438 static void obex_srm_init(obex_srm_t * obex_srm){
439     obex_srm->srm_value = OBEX_SRM_DISABLE;
440     obex_srm->srmp_value = OBEX_SRMP_NEXT;
441 }
442 static void pbap_client_yml_append_character(yxml_t * xml_parser, char * buffer, uint16_t buffer_size){
443     // "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."
444     uint16_t char_len = strlen(xml_parser->data);
445     btstack_assert(char_len <= 4);
446     uint16_t dest_len = strlen(buffer);
447     uint16_t zero_pos = dest_len + char_len;
448     if (zero_pos >= buffer_size) return;
449     memcpy(&buffer[dest_len], xml_parser->data, char_len);
450     buffer[zero_pos] = '\0';
451 }
452 
453 static void pbap_client_process_vcard_list_body(const uint8_t * data, uint16_t data_len){
454     while (data_len--) {
455         yxml_ret_t r = yxml_parse(&pbap_client->xml_parser, *data++);
456         switch (r) {
457             case YXML_ELEMSTART:
458                 pbap_client->parser_card_found = strcmp("card", pbap_client->xml_parser.elem) == 0;
459                 break;
460             case YXML_ELEMEND:
461                 if (pbap_client->parser_card_found) {
462                     pbap_client_emit_card_result_event(pbap_client, pbap_client->parser_name,
463                                                        pbap_client->parser_handle);
464                 }
465                 pbap_client->parser_card_found = false;
466                 break;
467             case YXML_ATTRSTART:
468                 if (!pbap_client->parser_card_found) break;
469                 if (strcmp("name", pbap_client->xml_parser.attr) == 0) {
470                     pbap_client->parser_name_found = true;
471                     pbap_client->parser_name[0] = 0;
472                     break;
473                 }
474                 if (strcmp("handle", pbap_client->xml_parser.attr) == 0) {
475                     pbap_client->parser_handle_found = true;
476                     pbap_client->parser_handle[0] = 0;
477                     break;
478                 }
479                 break;
480             case YXML_ATTRVAL:
481                 if (pbap_client->parser_name_found) {
482                     pbap_client_yml_append_character(&pbap_client->xml_parser,
483                                                      pbap_client->parser_name,
484                                                      sizeof(pbap_client->parser_name));
485                     break;
486                 }
487                 if (pbap_client->parser_handle_found) {
488                     pbap_client_yml_append_character(&pbap_client->xml_parser,
489                                                      pbap_client->parser_handle,
490                                                      sizeof(pbap_client->parser_handle));
491                     break;
492                 }
493                 break;
494             case YXML_ATTREND:
495                 pbap_client->parser_name_found = false;
496                 pbap_client->parser_handle_found = false;
497                 break;
498             default:
499                 break;
500         }
501     }
502 }
503 
504 static void pbap_client_parser_callback_connect(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){
505     pbap_client_t * client = (pbap_client_t *) user_data;
506     switch (header_id){
507         case OBEX_HEADER_CONNECTION_ID:
508             if (obex_parser_header_store(client->obex_header_buffer, sizeof(client->obex_header_buffer), total_len, data_offset, data_buffer, data_len) == OBEX_PARSER_HEADER_COMPLETE){
509                 goep_client_set_connection_id(client->goep_cid, big_endian_read_32(client->obex_header_buffer, 0));
510             }
511             break;
512         case OBEX_HEADER_AUTHENTICATION_CHALLENGE:
513             obex_auth_parser_process_data(&client->obex_auth_parser, data_buffer, data_len);
514             break;
515         default:
516             break;
517     }
518 }
519 
520 static void pbap_client_parser_callback_get_phonebook_size(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){
521     UNUSED(total_len);
522     UNUSED(data_offset);
523     pbap_client_t *client = (pbap_client_t *) user_data;
524     switch (header_id) {
525         case OBEX_HEADER_APPLICATION_PARAMETERS:
526             pbap_client_phoneboook_size_parser_process_data(&client->phonebook_size_parser, data_buffer, data_len);
527             break;
528         default:
529             break;
530     }
531 }
532 
533 static void pbap_client_parser_callback_get_operation(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){
534     pbap_client_t *client = (pbap_client_t *) user_data;
535     switch (header_id) {
536         case OBEX_HEADER_SINGLE_RESPONSE_MODE:
537             obex_parser_header_store(&client->obex_srm.srm_value, 1, total_len, data_offset, data_buffer, data_len);
538             break;
539         case OBEX_HEADER_SINGLE_RESPONSE_MODE_PARAMETER:
540             obex_parser_header_store(&client->obex_srm.srmp_value, 1, total_len, data_offset, data_buffer, data_len);
541             break;
542         case OBEX_HEADER_BODY:
543         case OBEX_HEADER_END_OF_BODY:
544             switch(pbap_client->state){
545                 case PBAP_W4_PHONEBOOK:
546                 case PBAP_W4_GET_CARD_ENTRY_COMPLETE:
547                     client->client_handler(PBAP_DATA_PACKET, client->cid, (uint8_t *) data_buffer, data_len);
548                     if (data_offset + data_len == total_len){
549                         client->flow_wait_for_user = true;
550                     }
551                     break;
552                 case PBAP_W4_GET_CARD_LIST_COMPLETE:
553                     pbap_client_process_vcard_list_body(data_buffer, data_len);
554                     break;
555                 default:
556                     btstack_unreachable();
557                     break;
558             }
559             break;
560         default:
561             // ignore other headers
562             break;
563     }
564 }
565 
566 static uint16_t pbap_client_application_params_add_vcard_selector(const pbap_client_t * client, uint8_t * application_parameters){
567     uint16_t pos = 0;
568     if (client->vcard_selector_supported){
569         // vCard Selector
570         if (pbap_client->vcard_selector){
571             application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_VCARD_SELECTOR;
572             application_parameters[pos++] = 8;
573             memset(&application_parameters[pos], 0, 4);
574             pos += 4;
575             big_endian_store_32(application_parameters, pos, client->vcard_selector);
576             pos += 4;
577         }
578         // vCard Selector Operator
579         if (client->vcard_selector_operator != PBAP_VCARD_SELECTOR_OPERATOR_OR){
580             application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_VCARD_SELECTOR_OPERATOR;
581             application_parameters[pos++] = 1;
582             application_parameters[pos++] = client->vcard_selector_operator;
583         }
584     }
585     return pos;
586 }
587 
588 static uint16_t pbap_client_application_params_add_max_list_count(const pbap_client_t * client, uint8_t * application_parameters, uint16_t max_count){
589     UNUSED(client);
590     uint16_t pos = 0;
591     application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_MAX_LIST_COUNT;
592     application_parameters[pos++] = 2;
593     big_endian_store_16(application_parameters, 2, max_count);
594     pos += 2;
595     return pos;
596 }
597 
598 // max size: PBAP_MAX_PHONE_NUMBER_LEN + 5
599 static uint16_t pbap_client_application_params_add_phone_number(const pbap_client_t * client, uint8_t * application_parameters){
600     uint16_t pos = 0;
601     if (client->phone_number){
602         // Search by phone number
603         uint16_t phone_number_len = btstack_min(PBAP_MAX_PHONE_NUMBER_LEN, strlen(client->phone_number));
604         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_SEARCH_VALUE;
605         application_parameters[pos++] = phone_number_len;
606         (void)memcpy(&application_parameters[pos],
607                      pbap_client->phone_number, phone_number_len);
608         pos += phone_number_len;
609         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_SEARCH_PROPERTY;
610         application_parameters[pos++] = 1;
611         application_parameters[pos++] = 0x01; // Number
612     }
613     return pos;
614 }
615 
616 static uint16_t pbap_client_application_params_add_property_selector(const pbap_client_t * client, uint8_t * application_parameters){
617     // TODO: support format
618     uint16_t pos = 0;
619     uint32_t property_selector_lower = client->property_selector;
620     if (strncmp(pbap_client->vcard_name, "X-BT-UID:", 9) == 0) {
621         property_selector_lower |= 1U << 31;
622     }
623     if (strncmp(pbap_client->vcard_name, "X-BT-UCI:", 9) == 0) {
624         property_selector_lower |= 1U << 30;
625     }
626     if (property_selector_lower != 0){
627         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_PROPERTY_SELECTOR;
628         application_parameters[pos++] = 8;
629         big_endian_store_32(application_parameters, pos, 0);    // upper 32-bits are reserved/unused so far
630         pos += 4;
631         big_endian_store_32(application_parameters, pos, property_selector_lower);
632         pos += 4;
633     }
634     return pos;
635 }
636 
637 // Mandatory if the PSE advertises a PbapSupportedFeatures attribute in its SDP record, else excluded.
638 static uint16_t pbap_client_application_parameters_add_supported_features(const pbap_client_t * client, uint8_t *application_parameters) {
639     uint16_t pos = 0;
640     if (goep_client_get_pbap_supported_features(client->goep_cid) != PBAP_FEATURES_NOT_PRESENT){
641         application_parameters[pos++] = PBAP_APPLICATION_PARAMETER_PBAP_SUPPORTED_FEATURES;
642         application_parameters[pos++] = 4;
643         big_endian_store_32(application_parameters, 2, pbap_client_supported_features);
644         pos += 4;
645     }
646     return pos;
647 }
648 
649 static void pbap_client_add_application_parameters(const pbap_client_t * client, uint8_t * application_parameters, uint16_t len){
650     if (len > 0){
651         goep_client_header_add_application_parameters(client->goep_cid, &application_parameters[0], len);
652     }
653 }
654 
655 static void pbap_client_prepare_srm_header(const pbap_client_t * client){
656     if (!client->flow_control_enabled && goep_client_version_20_or_higher(client->goep_cid)){
657         goep_client_header_add_srm_enable(client->goep_cid);
658         pbap_client->srm_state = SRM_W4_CONFIRM;
659     }
660 }
661 
662 static void pbap_client_prepare_get_operation(pbap_client_t * client){
663     obex_parser_init_for_response(&client->obex_parser, OBEX_OPCODE_GET, pbap_client_parser_callback_get_operation, pbap_client);
664     obex_srm_init(&client->obex_srm);
665     client->obex_parser_waiting_for_response = true;
666 }
667 
668 static void pbap_handle_can_send_now(void){
669     uint16_t path_element_start;
670     uint16_t path_element_len;
671     const char * path_element;
672     uint8_t  application_parameters[PBAP_MAX_PHONE_NUMBER_LEN + 10];
673     uint8_t  challenge_response[36];
674     uint16_t pos;
675 
676     MD5_CTX md5_ctx;
677 
678     if (pbap_client->abort_operation){
679         pbap_client->abort_operation = 0;
680         // prepare request
681         goep_client_request_create_abort(pbap_client->goep_cid);
682         // state
683         pbap_client->state = PBAP_W4_ABORT_COMPLETE;
684         // prepare response
685         obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_ABORT, NULL, pbap_client);
686         obex_srm_init(&pbap_client->obex_srm);
687         pbap_client->obex_parser_waiting_for_response = true;
688         // send packet
689         goep_client_execute(pbap_client->goep_cid);
690         return;
691     }
692 
693     switch (pbap_client->state){
694         case PBAP_W2_SEND_CONNECT_REQUEST:
695             // prepare request
696             goep_client_request_create_connect(pbap_client->goep_cid, OBEX_VERSION, 0, OBEX_MAX_PACKETLEN_DEFAULT);
697             goep_client_header_add_target(pbap_client->goep_cid, pbap_uuid, 16);
698             pos = 0;
699             pos += pbap_client_application_parameters_add_supported_features(pbap_client, &application_parameters[pos]);
700             pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
701             // state
702             pbap_client->state = PBAP_W4_CONNECT_RESPONSE;
703             // prepare response
704             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_CONNECT, pbap_client_parser_callback_connect, pbap_client);
705             obex_auth_parser_init(&pbap_client->obex_auth_parser);
706             obex_srm_init(&pbap_client->obex_srm);
707             pbap_client->obex_parser_waiting_for_response = true;
708             // send packet
709             goep_client_execute(pbap_client->goep_cid);
710             break;
711         case PBAP_W2_SEND_AUTHENTICATED_CONNECT:
712             // prepare request
713             goep_client_request_create_connect(pbap_client->goep_cid, OBEX_VERSION, 0, OBEX_MAX_PACKETLEN_DEFAULT);
714             goep_client_header_add_target(pbap_client->goep_cid, pbap_uuid, 16);
715             // setup authentication challenge response
716             pos = 0;
717             challenge_response[pos++] = 0;  // Tag Digest
718             challenge_response[pos++] = 16; // Len
719             // calculate md5
720             MD5_Init(&md5_ctx);
721             MD5_Update(&md5_ctx, pbap_client->obex_auth_parser.authentication_nonce, 16);
722             MD5_Update(&md5_ctx, &collon, 1);
723             MD5_Update(&md5_ctx, pbap_client->authentication_password, strlen(pbap_client->authentication_password));
724             MD5_Final(&challenge_response[pos], &md5_ctx);
725             pos += 16;
726             challenge_response[pos++] = 2;  // Tag Nonce
727             challenge_response[pos++] = 16; // Len
728             (void)memcpy(&challenge_response[pos], pbap_client->obex_auth_parser.authentication_nonce, 16);
729             pos += 16;
730             goep_client_header_add_challenge_response(pbap_client->goep_cid, challenge_response, pos);
731             // state
732             pbap_client->state = PBAP_W4_CONNECT_RESPONSE;
733             // prepare response
734             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_CONNECT, pbap_client_parser_callback_connect, pbap_client);
735             obex_srm_init(&pbap_client->obex_srm);
736             pbap_client->obex_parser_waiting_for_response = true;
737             // send packet
738             goep_client_execute(pbap_client->goep_cid);
739             break;
740         case PBAP_W2_SEND_DISCONNECT_REQUEST:
741             // prepare request
742             goep_client_request_create_disconnect(pbap_client->goep_cid);
743             // state
744             pbap_client->state = PBAP_W4_DISCONNECT_RESPONSE;
745             // prepare response
746             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_DISCONNECT, NULL, pbap_client);
747             obex_srm_init(&pbap_client->obex_srm);
748             pbap_client->obex_parser_waiting_for_response = true;
749             // send packet
750             goep_client_execute(pbap_client->goep_cid);
751             return;
752         case PBAP_W2_GET_PHONEBOOK_SIZE:
753             // prepare request
754             goep_client_request_create_get(pbap_client->goep_cid);
755             pbap_client_prepare_srm_header(pbap_client);
756             goep_client_header_add_name(pbap_client->goep_cid, pbap_client->phonebook_path);
757             goep_client_header_add_type(pbap_client->goep_cid, pbap_phonebook_type);
758 
759             pos = 0;
760             pos += pbap_client_application_params_add_vcard_selector(pbap_client, &application_parameters[pos]);
761             pos += pbap_client_application_params_add_max_list_count(pbap_client, &application_parameters[pos], 0); // just get size
762             pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
763 
764             // state
765             pbap_client->state = PBAP_W4_GET_PHONEBOOK_SIZE_COMPLETE;
766             // prepare response
767             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_GET, pbap_client_parser_callback_get_phonebook_size, pbap_client);
768             obex_srm_init(&pbap_client->obex_srm);
769             pbap_client_phonebook_size_parser_init(&pbap_client->phonebook_size_parser);
770             pbap_client->obex_parser_waiting_for_response = true;
771             // send packet
772             goep_client_execute(pbap_client->goep_cid);
773             break;
774         case PBAP_W2_PULL_PHONEBOOK:
775             // prepare request
776             goep_client_request_create_get(pbap_client->goep_cid);
777             if (pbap_client->request_number == 0){
778                 pbap_client_prepare_srm_header(pbap_client);
779                 goep_client_header_add_name(pbap_client->goep_cid, pbap_client->phonebook_path);
780                 goep_client_header_add_type(pbap_client->goep_cid, pbap_phonebook_type);
781 
782                 pos = 0;
783                 pos += pbap_client_application_params_add_vcard_selector(pbap_client, &application_parameters[pos]);
784                 pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
785             }
786             // state
787             pbap_client->state = PBAP_W4_PHONEBOOK;
788             pbap_client->flow_next_triggered = 0;
789             pbap_client->flow_wait_for_user = 0;
790             // prepare response
791             pbap_client_prepare_get_operation(pbap_client);
792             // send packet
793             pbap_client->request_number++;
794             goep_client_execute(pbap_client->goep_cid);
795             break;
796         case PBAP_W2_GET_CARD_LIST:
797             // prepare request
798             goep_client_request_create_get(pbap_client->goep_cid);
799             if (pbap_client->request_number == 0){
800                 pbap_client_prepare_srm_header(pbap_client);
801                 goep_client_header_add_name(pbap_client->goep_cid, pbap_client->phonebook_path);
802                 goep_client_header_add_type(pbap_client->goep_cid, pbap_vcard_listing_type);
803 
804                 pos = 0;
805                 pos += pbap_client_application_params_add_vcard_selector(pbap_client, &application_parameters[pos]);
806                 pos += pbap_client_application_params_add_phone_number(pbap_client, &application_parameters[pos]);
807                 pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
808             }
809             // state
810             pbap_client->state = PBAP_W4_GET_CARD_LIST_COMPLETE;
811             // prepare response
812             pbap_client_prepare_get_operation(pbap_client);
813             // send packet
814             pbap_client->request_number++;
815             goep_client_execute(pbap_client->goep_cid);
816             break;
817         case PBAP_W2_GET_CARD_ENTRY:
818             // prepare request
819             goep_client_request_create_get(pbap_client->goep_cid);
820             if (pbap_client->request_number == 0){
821                 pbap_client_prepare_srm_header(pbap_client);
822                 goep_client_header_add_name(pbap_client->goep_cid, pbap_client->vcard_name);
823                 goep_client_header_add_type(pbap_client->goep_cid, pbap_vcard_entry_type);
824 
825                 pos = 0;
826                 pos += pbap_client_application_params_add_property_selector(pbap_client, &application_parameters[pos]);
827                 pbap_client_add_application_parameters(pbap_client, application_parameters, pos);
828             }
829             // state
830             pbap_client->state = PBAP_W4_GET_CARD_ENTRY_COMPLETE;
831             // prepare response
832             pbap_client_prepare_get_operation(pbap_client);
833             // send packet
834             pbap_client->request_number++;
835             goep_client_execute(pbap_client->goep_cid);
836             break;
837         case PBAP_W2_SET_PATH_ROOT:
838             // prepare request
839             goep_client_request_create_set_path(pbap_client->goep_cid, 1 << 1); // Don’t create directory
840             goep_client_header_add_name(pbap_client->goep_cid, "");
841             // state
842             pbap_client->state = PBAP_W4_SET_PATH_ROOT_COMPLETE;
843             // prepare response
844             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_SETPATH, NULL, pbap_client);
845             obex_srm_init(&pbap_client->obex_srm);
846             pbap_client->obex_parser_waiting_for_response = true;
847             // send packet
848             goep_client_execute(pbap_client->goep_cid);
849             break;
850         case PBAP_W2_SET_PATH_ELEMENT:
851             // prepare request
852             // find '/' or '\0'
853             path_element_start = pbap_client->set_path_offset;
854             while ((pbap_client->current_folder[pbap_client->set_path_offset] != '\0') &&
855                 (pbap_client->current_folder[pbap_client->set_path_offset] != '/')){
856                 pbap_client->set_path_offset++;
857             }
858             path_element_len = pbap_client->set_path_offset-path_element_start;
859             path_element = (const char *) &pbap_client->current_folder[path_element_start];
860 
861             // skip /
862             if (pbap_client->current_folder[pbap_client->set_path_offset] == '/'){
863                 pbap_client->set_path_offset++;
864             }
865 
866             goep_client_request_create_set_path(pbap_client->goep_cid, 1 << 1); // Don’t create directory
867             goep_client_header_add_name_prefix(pbap_client->goep_cid, path_element, path_element_len); // next element
868             // state
869             pbap_client->state = PBAP_W4_SET_PATH_ELEMENT_COMPLETE;
870             // prepare response
871             obex_parser_init_for_response(&pbap_client->obex_parser, OBEX_OPCODE_SETPATH, NULL, pbap_client);
872             obex_srm_init(&pbap_client->obex_srm);
873             pbap_client->obex_parser_waiting_for_response = true;
874             // send packet
875             goep_client_execute(pbap_client->goep_cid);
876             break;
877         default:
878             break;
879     }
880 }
881 
882 static void pbap_client_handle_srm_headers(pbap_client_t *context) {
883     const obex_srm_t * obex_srm = &pbap_client->obex_srm;
884     // Update SRM state based on SRM headers
885     switch (context->srm_state){
886         case SRM_W4_CONFIRM:
887             switch (obex_srm->srm_value){
888                 case OBEX_SRM_ENABLE:
889                     switch (obex_srm->srmp_value){
890                         case OBEX_SRMP_WAIT:
891                             context->srm_state = SRM_ENABLED_BUT_WAITING;
892                             break;
893                         default:
894                             context->srm_state = SRM_ENABLED;
895                             break;
896                     }
897                     break;
898                 default:
899                     context->srm_state = SRM_DISABLED;
900                     break;
901             }
902             break;
903         case SRM_ENABLED_BUT_WAITING:
904             switch (obex_srm->srmp_value){
905                 case OBEX_SRMP_WAIT:
906                     context->srm_state = SRM_ENABLED_BUT_WAITING;
907                     break;
908                 default:
909                     context->srm_state = SRM_ENABLED;
910                     break;
911             }
912             break;
913         default:
914             break;
915     }
916     log_info("SRM state %u", context->srm_state);
917 }
918 
919 static void pbap_packet_handler_hci(uint8_t *packet, uint16_t size){
920     UNUSED(size);
921     uint8_t status;
922     switch (hci_event_packet_get_type(packet)) {
923         case HCI_EVENT_GOEP_META:
924             switch (hci_event_goep_meta_get_subevent_code(packet)){
925                 case GOEP_SUBEVENT_CONNECTION_OPENED:
926                     status = goep_subevent_connection_opened_get_status(packet);
927                     pbap_client->con_handle = goep_subevent_connection_opened_get_con_handle(packet);
928                     pbap_client->incoming = goep_subevent_connection_opened_get_incoming(packet);
929                     goep_subevent_connection_opened_get_bd_addr(packet, pbap_client->bd_addr);
930                     if (status){
931                         log_info("pbap: connection failed %u", status);
932                         pbap_client->state = PBAP_INIT;
933                         pbap_client_emit_connected_event(pbap_client, status);
934                     } else {
935                         log_info("pbap: connection established");
936                         pbap_client->goep_cid = goep_subevent_connection_opened_get_goep_cid(packet);
937                         pbap_client->state = PBAP_W2_SEND_CONNECT_REQUEST;
938                         goep_client_request_can_send_now(pbap_client->goep_cid);
939                     }
940                     break;
941                 case GOEP_SUBEVENT_CONNECTION_CLOSED:
942                     if (pbap_client->state > PBAP_CONNECTED){
943                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_DISCONNECTED);
944                     }
945                     pbap_client->state = PBAP_INIT;
946                     pbap_client_emit_connection_closed_event(pbap_client);
947                     break;
948                 case GOEP_SUBEVENT_CAN_SEND_NOW:
949                     pbap_handle_can_send_now();
950                     break;
951                 default:
952                     break;
953             }
954             break;
955         default:
956             break;
957     }
958 }
959 
960 static void pbap_packet_handler_goep(uint8_t *packet, uint16_t size){
961     if (pbap_client->obex_parser_waiting_for_response == false) return;
962 
963     obex_parser_object_state_t parser_state;
964     parser_state = obex_parser_process_data(&pbap_client->obex_parser, packet, size);
965     if (parser_state == OBEX_PARSER_OBJECT_STATE_COMPLETE){
966         pbap_client->obex_parser_waiting_for_response = false;
967         obex_parser_operation_info_t op_info;
968         obex_parser_get_operation_info(&pbap_client->obex_parser, &op_info);
969         switch (pbap_client->state){
970             case PBAP_W4_CONNECT_RESPONSE:
971                 switch (op_info.response_code) {
972                     case OBEX_RESP_SUCCESS:
973                         pbap_client->state = PBAP_CONNECTED;
974                         pbap_client->vcard_selector_supported = pbap_client_supported_features & goep_client_get_pbap_supported_features( pbap_client->goep_cid) & PBAP_SUPPORTED_FEATURES_VCARD_SELECTING;
975                         pbap_client_emit_connected_event(pbap_client, ERROR_CODE_SUCCESS);
976                         break;
977                     case OBEX_RESP_UNAUTHORIZED:
978                         pbap_client->state = PBAP_W4_USER_AUTHENTICATION;
979                         pbap_client_emit_authentication_event(pbap_client, pbap_client->obex_auth_parser.authentication_options);
980                         break;
981                     default:
982                         log_info("pbap: obex connect failed, result 0x%02x", packet[0]);
983                         pbap_client->state = PBAP_INIT;
984                         pbap_client_emit_connected_event(pbap_client, OBEX_CONNECT_FAILED);
985                         break;
986                 }
987                 break;
988             case PBAP_W4_DISCONNECT_RESPONSE:
989                 goep_client_disconnect(pbap_client->goep_cid);
990                 break;
991             case PBAP_W4_SET_PATH_ROOT_COMPLETE:
992             case PBAP_W4_SET_PATH_ELEMENT_COMPLETE:
993                 switch (op_info.response_code) {
994                     case OBEX_RESP_SUCCESS:
995                         // more path?
996                         if (pbap_client->current_folder[pbap_client->set_path_offset]) {
997                             pbap_client->state = PBAP_W2_SET_PATH_ELEMENT;
998                             goep_client_request_can_send_now(pbap_client->goep_cid);
999                         } else {
1000                             pbap_client->current_folder = NULL;
1001                             pbap_client->state = PBAP_CONNECTED;
1002                             pbap_client_emit_operation_complete_event(pbap_client, ERROR_CODE_SUCCESS);
1003                         }
1004                         break;
1005                     case OBEX_RESP_NOT_FOUND:
1006                         pbap_client->state = PBAP_CONNECTED;
1007                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_NOT_FOUND);
1008                         break;
1009                     default:
1010                         pbap_client->state = PBAP_CONNECTED;
1011                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_UNKNOWN_ERROR);
1012                         break;
1013                 }
1014                 break;
1015             case PBAP_W4_PHONEBOOK:
1016                 switch (op_info.response_code) {
1017                     case OBEX_RESP_CONTINUE:
1018                         pbap_client_handle_srm_headers(pbap_client);
1019                         if (pbap_client->srm_state == SRM_ENABLED) {
1020                             // prepare response
1021                             pbap_client_prepare_get_operation(pbap_client);
1022                             break;
1023                         }
1024                         pbap_client->state = PBAP_W2_PULL_PHONEBOOK;
1025                         if (!pbap_client->flow_control_enabled || !pbap_client->flow_wait_for_user ||
1026                             pbap_client->flow_next_triggered) {
1027                             goep_client_request_can_send_now(pbap_client->goep_cid);
1028                         }
1029                         break;
1030                     case OBEX_RESP_SUCCESS:
1031                         pbap_client->state = PBAP_CONNECTED;
1032                         pbap_client_emit_operation_complete_event(pbap_client, ERROR_CODE_SUCCESS);
1033                         break;
1034                     default:
1035                         log_info("unexpected response 0x%02x", packet[0]);
1036                         pbap_client->state = PBAP_CONNECTED;
1037                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_UNKNOWN_ERROR);
1038                         break;
1039                 }
1040                 break;
1041             case PBAP_W4_GET_PHONEBOOK_SIZE_COMPLETE:
1042                 switch (op_info.response_code) {
1043                     case OBEX_RESP_SUCCESS:
1044                         if (pbap_client->phonebook_size_parser.have_size) {
1045                             uint16_t phonebook_size = big_endian_read_16(pbap_client->phonebook_size_parser.size_buffer, 0);
1046                             pbap_client->state = PBAP_CONNECTED;
1047                             pbap_client_emit_phonebook_size_event(pbap_client, 0, phonebook_size);
1048                             break;
1049                         }
1050                         /* fall through */
1051                     default:
1052                         pbap_client->state = PBAP_CONNECTED;
1053                         pbap_client_emit_phonebook_size_event(pbap_client, OBEX_UNKNOWN_ERROR, 0);
1054                         break;
1055                 }
1056                 break;
1057             case PBAP_W4_GET_CARD_LIST_COMPLETE:
1058                 switch (op_info.response_code) {
1059                     case OBEX_RESP_CONTINUE:
1060                         // handle continue
1061                         pbap_client_handle_srm_headers(pbap_client);
1062                         if (pbap_client->srm_state == SRM_ENABLED) {
1063                             // prepare response
1064                             pbap_client_prepare_get_operation(pbap_client);
1065                             break;
1066                         }
1067                         pbap_client->state = PBAP_W2_GET_CARD_LIST;
1068                         goep_client_request_can_send_now(pbap_client->goep_cid);
1069                         break;
1070                     case OBEX_RESP_SUCCESS:
1071                         // done
1072                         pbap_client->state = PBAP_CONNECTED;
1073                         pbap_client_emit_operation_complete_event(pbap_client, ERROR_CODE_SUCCESS);
1074                         break;
1075                     case OBEX_RESP_NOT_ACCEPTABLE:
1076                         pbap_client->state = PBAP_CONNECTED;
1077                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_NOT_ACCEPTABLE);
1078                         break;
1079                     default:
1080                         log_info("unexpected response 0x%02x", packet[0]);
1081                         pbap_client->state = PBAP_CONNECTED;
1082                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_UNKNOWN_ERROR);
1083                         break;
1084                 }
1085                 break;
1086             case PBAP_W4_GET_CARD_ENTRY_COMPLETE:
1087                 switch (op_info.response_code) {
1088                     case OBEX_RESP_CONTINUE:
1089                         pbap_client_handle_srm_headers(pbap_client);
1090                         if (pbap_client->srm_state == SRM_ENABLED) {
1091                             // prepare response
1092                             pbap_client_prepare_get_operation(pbap_client);
1093                             break;
1094                         }
1095                         pbap_client->state = PBAP_W2_GET_CARD_ENTRY;
1096                         goep_client_request_can_send_now(pbap_client->goep_cid);
1097                         break;
1098                     case OBEX_RESP_SUCCESS:
1099                         pbap_client->state = PBAP_CONNECTED;
1100                         pbap_client_emit_operation_complete_event(pbap_client, ERROR_CODE_SUCCESS);
1101                         break;
1102                     case OBEX_RESP_NOT_ACCEPTABLE:
1103                         pbap_client->state = PBAP_CONNECTED;
1104                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_NOT_ACCEPTABLE);
1105                         break;
1106                     default:
1107                         log_info("unexpected response 0x%02x", packet[0]);
1108                         pbap_client->state = PBAP_CONNECTED;
1109                         pbap_client_emit_operation_complete_event(pbap_client, OBEX_UNKNOWN_ERROR);
1110                         break;
1111                 }
1112                 break;
1113             case PBAP_W4_ABORT_COMPLETE:
1114                 pbap_client->state = PBAP_CONNECTED;
1115                 pbap_client_emit_operation_complete_event(pbap_client, OBEX_ABORTED);
1116                 break;
1117             default:
1118                 btstack_unreachable();
1119                 break;
1120         }
1121     }
1122 }
1123 
1124 static void pbap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
1125     UNUSED(channel); // ok: there is no channel
1126     UNUSED(size);    // ok: handling own geop events
1127 
1128     switch (packet_type){
1129         case HCI_EVENT_PACKET:
1130             pbap_packet_handler_hci(packet, size);
1131             break;
1132         case GOEP_DATA_PACKET:
1133             pbap_packet_handler_goep(packet, size);
1134             break;
1135         default:
1136             break;
1137     }
1138 }
1139 
1140 static void pbap_client_reset_state(void) {
1141     pbap_client_supported_features =
1142             PBAP_SUPPORTED_FEATURES_DOWNLOAD |
1143             PBAP_SUPPORTED_FEATURES_BROWSING |
1144             PBAP_SUPPORTED_FEATURES_DATABASE_IDENTIFIER |
1145             PBAP_SUPPORTED_FEATURES_FOLDER_VERSION_COUNTERS |
1146             PBAP_SUPPORTED_FEATURES_VCARD_SELECTING |
1147             PBAP_SUPPORTED_FEATURES_ENHANCED_MISSED_CALLS |
1148             PBAP_SUPPORTED_FEATURES_DEFAULT_CONTACT_IMAGE_FORMAT |
1149             PBAP_SUPPORTED_FEATURES_X_BT_UCI_VCARD_PROPERTY |
1150             PBAP_SUPPORTED_FEATURES_X_BT_UID_VCARD_PROPERTY |
1151             PBAP_SUPPORTED_FEATURES_CONTACT_REFERENCING;
1152     pbap_client->state = PBAP_INIT;
1153     pbap_client->cid = 1;
1154 }
1155 
1156 void pbap_client_init(void){
1157     pbap_client_reset_state();
1158 }
1159 
1160 void pbap_client_deinit(void){
1161     pbap_client_reset_state();
1162     memset(pbap_client, 0, sizeof(pbap_client_t));
1163 }
1164 
1165 uint8_t pbap_connect(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t * out_cid){
1166     if (pbap_client->state != PBAP_INIT){
1167         return BTSTACK_MEMORY_ALLOC_FAILED;
1168     }
1169 
1170     pbap_client->state = PBAP_W4_GOEP_CONNECTION;
1171     pbap_client->client_handler = handler;
1172     pbap_client->vcard_selector = 0;
1173     pbap_client->vcard_selector_operator = PBAP_VCARD_SELECTOR_OPERATOR_OR;
1174 
1175     uint8_t err = goep_client_create_connection(&pbap_packet_handler, addr, BLUETOOTH_SERVICE_CLASS_PHONEBOOK_ACCESS_PSE, &pbap_client->goep_cid);
1176     *out_cid = pbap_client->cid;
1177     if (err) return err;
1178     return ERROR_CODE_SUCCESS;
1179 }
1180 
1181 uint8_t pbap_disconnect(uint16_t pbap_cid){
1182     UNUSED(pbap_cid);
1183     if (pbap_client->state < PBAP_CONNECTED){
1184         return BTSTACK_BUSY;
1185     }
1186     pbap_client->state = PBAP_W2_SEND_DISCONNECT_REQUEST;
1187     goep_client_request_can_send_now(pbap_client->goep_cid);
1188     return ERROR_CODE_SUCCESS;
1189 }
1190 
1191 uint8_t pbap_get_phonebook_size(uint16_t pbap_cid, const char * path){
1192     UNUSED(pbap_cid);
1193     if (pbap_client->state != PBAP_CONNECTED){
1194         return BTSTACK_BUSY;
1195     }
1196     pbap_client->state = PBAP_W2_GET_PHONEBOOK_SIZE;
1197     pbap_client->phonebook_path = path;
1198     pbap_client->request_number = 0;
1199     goep_client_request_can_send_now(pbap_client->goep_cid);
1200     return ERROR_CODE_SUCCESS;
1201 }
1202 
1203 uint8_t pbap_pull_phonebook(uint16_t pbap_cid, const char * path){
1204     UNUSED(pbap_cid);
1205     if (pbap_client->state != PBAP_CONNECTED){
1206         return BTSTACK_BUSY;
1207     }
1208     pbap_client->state = PBAP_W2_PULL_PHONEBOOK;
1209     pbap_client->phonebook_path = path;
1210     pbap_client->request_number = 0;
1211     goep_client_request_can_send_now(pbap_client->goep_cid);
1212     return ERROR_CODE_SUCCESS;
1213 }
1214 
1215 uint8_t pbap_set_phonebook(uint16_t pbap_cid, const char * path){
1216     UNUSED(pbap_cid);
1217     if (pbap_client->state != PBAP_CONNECTED){
1218         return BTSTACK_BUSY;
1219     }
1220     pbap_client->state = PBAP_W2_SET_PATH_ROOT;
1221     pbap_client->current_folder = path;
1222     pbap_client->set_path_offset = 0;
1223     goep_client_request_can_send_now(pbap_client->goep_cid);
1224     return ERROR_CODE_SUCCESS;
1225 }
1226 
1227 uint8_t pbap_authentication_password(uint16_t pbap_cid, const char * password){
1228     UNUSED(pbap_cid);
1229     if (pbap_client->state != PBAP_W4_USER_AUTHENTICATION){
1230         return BTSTACK_BUSY;
1231     }
1232     pbap_client->state = PBAP_W2_SEND_AUTHENTICATED_CONNECT;
1233     pbap_client->authentication_password = password;
1234     goep_client_request_can_send_now(pbap_client->goep_cid);
1235     return ERROR_CODE_SUCCESS;
1236 }
1237 
1238 uint8_t pbap_pull_vcard_listing(uint16_t pbap_cid, const char * path){
1239     UNUSED(pbap_cid);
1240     if (pbap_client->state != PBAP_CONNECTED){
1241         return BTSTACK_BUSY;
1242     }
1243     pbap_client->state = PBAP_W2_GET_CARD_LIST;
1244     pbap_client->phonebook_path = path;
1245     pbap_client->phone_number = NULL;
1246     pbap_client->request_number = 0;
1247     pbap_client_vcard_listing_init_parser(pbap_client);
1248     goep_client_request_can_send_now(pbap_client->goep_cid);
1249     return ERROR_CODE_SUCCESS;
1250 }
1251 
1252 uint8_t pbap_pull_vcard_entry(uint16_t pbap_cid, const char * path){
1253     UNUSED(pbap_cid);
1254     if (pbap_client->state != PBAP_CONNECTED){
1255         return BTSTACK_BUSY;
1256     }
1257     pbap_client->state = PBAP_W2_GET_CARD_ENTRY;
1258     // pbap_client->phonebook_path = NULL;
1259     // pbap_client->phone_number = NULL;
1260     pbap_client->vcard_name = path;
1261     pbap_client->request_number = 0;
1262     goep_client_request_can_send_now(pbap_client->goep_cid);
1263     return ERROR_CODE_SUCCESS;
1264 }
1265 
1266 uint8_t pbap_lookup_by_number(uint16_t pbap_cid, const char * phone_number){
1267     UNUSED(pbap_cid);
1268     if (pbap_client->state != PBAP_CONNECTED){
1269         return BTSTACK_BUSY;
1270     }
1271     pbap_client->state = PBAP_W2_GET_CARD_LIST;
1272     pbap_client->phonebook_path = pbap_vcard_listing_name;
1273     pbap_client->phone_number   = phone_number;
1274     pbap_client->request_number = 0;
1275     pbap_client_vcard_listing_init_parser(pbap_client);
1276     goep_client_request_can_send_now(pbap_client->goep_cid);
1277     return ERROR_CODE_SUCCESS;
1278 }
1279 
1280 uint8_t pbap_abort(uint16_t pbap_cid){
1281     UNUSED(pbap_cid);
1282     if ((pbap_client->state < PBAP_CONNECTED) || (pbap_client->abort_operation != 0)){
1283         return ERROR_CODE_COMMAND_DISALLOWED;
1284     }
1285     log_info("abort current operation, state 0x%02x", pbap_client->state);
1286     pbap_client->abort_operation = 1;
1287     return ERROR_CODE_SUCCESS;
1288 }
1289 
1290 uint8_t pbap_next_packet(uint16_t pbap_cid){
1291     // log_info("pbap_next_packet, state %x", pbap_client->state);
1292     UNUSED(pbap_cid);
1293     if (!pbap_client->flow_control_enabled){
1294         return ERROR_CODE_SUCCESS;
1295     }
1296     switch (pbap_client->state){
1297         case PBAP_W2_PULL_PHONEBOOK:
1298             goep_client_request_can_send_now(pbap_client->goep_cid);
1299             break;
1300         case PBAP_W4_PHONEBOOK:
1301             pbap_client->flow_next_triggered = 1;
1302             break;
1303         default:
1304             break;
1305     }
1306     return ERROR_CODE_SUCCESS;
1307 }
1308 
1309 uint8_t pbap_set_flow_control_mode(uint16_t pbap_cid, int enable){
1310     UNUSED(pbap_cid);
1311     if (pbap_client->state != PBAP_CONNECTED){
1312         return BTSTACK_BUSY;
1313     }
1314     pbap_client->flow_control_enabled = enable;
1315     return ERROR_CODE_SUCCESS;
1316 }
1317 
1318 uint8_t pbap_set_vcard_selector(uint16_t pbap_cid, uint32_t vcard_selector){
1319     UNUSED(pbap_cid);
1320     if (pbap_client->state != PBAP_CONNECTED){
1321         return BTSTACK_BUSY;
1322     }
1323     pbap_client->vcard_selector = vcard_selector;
1324     return ERROR_CODE_SUCCESS;
1325 }
1326 
1327 uint8_t pbap_set_vcard_selector_operator(uint16_t pbap_cid, int vcard_selector_operator){
1328     UNUSED(pbap_cid);
1329     if (pbap_client->state != PBAP_CONNECTED){
1330         return BTSTACK_BUSY;
1331     }
1332     pbap_client->vcard_selector_operator = vcard_selector_operator;
1333     return ERROR_CODE_SUCCESS;
1334 }
1335 
1336 uint8_t pbap_set_property_selector(uint16_t pbap_cid, uint32_t property_selector){
1337     UNUSED(pbap_cid);
1338     if (pbap_client->state != PBAP_CONNECTED){
1339         return BTSTACK_BUSY;
1340     }
1341     pbap_client->property_selector  = property_selector;
1342     return ERROR_CODE_SUCCESS;
1343 }
1344