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