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