32db9a4e0fab05210b745a74589afb6598b29bba
[platform/core/telephony/tel-plugin-imc.git] / src / imc_phonebook.c
1 /**
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact: Ankit Jogi <ankit.jogi@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <glib.h>
26
27 #include <tcore.h>
28 #include <server.h>
29 #include <core_object.h>
30 #include <plugin.h>
31 #include <hal.h>
32 #include <user_request.h>
33 #include <at.h>
34
35 #include <co_phonebook.h>
36 #include <co_sim.h>
37
38 #include "imc_phonebook.h"
39
40 /* Constants */
41 #define VAL_ZERO        0
42 #define VAL_ONE         1
43 #define VAL_TWO         2
44 #define VAL_THREE       3
45 #define VAL_FOUR        4
46 #define VAL_FIVE                5
47 #define VAL_SIX         6
48 #define VAL_SEVEN       7
49 #define VAL_EIGHT       8
50 #define VAL_NINE        9
51
52 /* Type Of Number and Number Plan */
53 #define IMC_TON_INTERNATIONAL           145
54 #define IMC_TON_UNKNOWN         129
55 #define IMC_NUM_PLAN_INTERNATIONAL      0x0070
56 #define IMC_NUM_PLAN_UNKNOWN            0x0060
57
58 #define IMC_PB_INFO_LENGTH              5
59
60 typedef struct {
61         GSList *used_index_fdn;
62         gboolean used_index_fdn_valid;
63
64         GSList *used_index_adn;
65         gboolean used_index_adn_valid;
66
67         GSList *used_index_sdn;
68         gboolean used_index_sdn_valid;
69
70         GSList *used_index_usim;
71         gboolean used_index_usim_valid;
72 } PrivateInfo;
73
74 /******************************************************************************
75  * Internal functions
76  *****************************************************************************/
77 static gint __phonebook_compare_index(gconstpointer a, gconstpointer b)
78 {
79         guint index1 = (guint)a;
80         guint index2 = (guint)b;
81
82         return index1 - index2;
83 }
84
85 static enum tel_phonebook_field_type __phonebook_convert_field_type(int field_type)
86 {
87         switch (field_type) {
88         case 1:
89                 return PB_FIELD_NUMBER;
90         case 2:
91                 return PB_FIELD_NAME;
92         case 3:
93                 return PB_FIELD_GRP;
94         case 4:
95                 return PB_FIELD_SNE;
96         case 5:
97                 return PB_FIELD_EMAIL1;
98         default:
99                 return 0;
100         }
101 }
102
103 static enum tel_phonebook_ton __phonebook_find_num_plan(int number_plan)
104 {
105         enum tel_phonebook_ton result;
106         dbg("number_plan : 0x%04x", number_plan);
107
108         if (number_plan & IMC_NUM_PLAN_INTERNATIONAL)
109                 result = PB_TON_INTERNATIONAL;
110         else
111                 result = PB_TON_UNKNOWN;
112
113         dbg("result : %d", result);
114
115         return result;
116 }
117
118 static gboolean __phonebook_get_pb_type_str(enum tel_phonebook_type pb_type,
119                 gchar **req_type_str)
120 {
121         g_assert(req_type_str != NULL);
122
123         switch (pb_type) {
124         case PB_TYPE_FDN:
125                 *req_type_str = g_strdup("FD");
126         break;
127         case PB_TYPE_ADN:
128         case PB_TYPE_USIM:
129                 *req_type_str = g_strdup("SM");
130         break;
131         case PB_TYPE_SDN:
132                 *req_type_str = g_strdup("SN");
133         break;
134         default:
135                 warn("Unsupported Phonebook type");
136                 *req_type_str = g_strdup("NS");
137         break;
138         }
139
140         return TRUE;
141 }
142
143 static gboolean __phonebook_check_and_select_type(CoreObject *co,
144         enum tel_phonebook_type req_pb_type, gchar **set_pb_cmd)
145 {
146         struct tel_phonebook_support_list *support_list;
147         enum tel_phonebook_type current_type;
148
149         /* Check whether pb_type is supported or not */
150         support_list = tcore_phonebook_get_support_list(co);
151         if (support_list) {
152                 if ((req_pb_type == PB_TYPE_FDN && support_list->b_fdn == FALSE)
153                                 || (req_pb_type == PB_TYPE_ADN && support_list->b_adn == FALSE)
154                                 || (req_pb_type == PB_TYPE_SDN && support_list->b_sdn == FALSE)
155                                 || (req_pb_type == PB_TYPE_USIM && support_list->b_usim == FALSE)) {
156                         err("Not supported Phonebook type");
157
158                         g_free(support_list);
159                         return FALSE;
160                 }
161                 g_free(support_list);
162         }
163
164         /* Check Current type & Request type */
165         current_type = tcore_phonebook_get_selected_type(co);
166         if (current_type != req_pb_type) {
167                 gchar *req_pb_type_str = NULL;
168
169                 __phonebook_get_pb_type_str(req_pb_type, &req_pb_type_str);
170                 dbg("Add AT-Command to change [%s] Type", req_pb_type_str);
171
172                 /* Select Phonebook type */
173                 *set_pb_cmd = g_strdup_printf("AT+CPBS=\"%s\";", req_pb_type_str);
174
175                 g_free(req_pb_type_str);
176         } else {
177                 *set_pb_cmd = g_strdup_printf("AT");
178         }
179
180         return TRUE;
181 }
182
183 static gboolean __phonebook_update_index_list_by_type(CoreObject *co,
184         enum tel_phonebook_type pb_type, guint req_index)
185 {
186         GSList *list = NULL;
187         PrivateInfo *private_info = tcore_object_ref_user_data(co);
188         g_assert(private_info != NULL);
189
190         switch (pb_type) {
191         case PB_TYPE_FDN:
192                 list = private_info->used_index_fdn;
193         break;
194
195         case PB_TYPE_ADN:
196                 list = private_info->used_index_adn;
197         break;
198
199         case PB_TYPE_SDN:
200                 list = private_info->used_index_sdn;
201         break;
202
203         case PB_TYPE_USIM:
204                 list = private_info->used_index_usim;
205         break;
206
207         default:
208                 warn("Unsupported Phonebook type: [%d]", pb_type);
209                 return FALSE;
210         }
211
212         /*
213          * Check if 'index' is already available (UPDATE operation).
214          */
215         while (list) {
216                 if ((guint)list->data == req_index) {
217                         /*
218                          * index 'present', no need to update
219                          */
220                         dbg("Index: [%d] present in Phonebook type: [%d]",
221                                 req_index, pb_type);
222
223                         return TRUE;
224                 }
225                 list = g_slist_next(list);
226         }
227
228         /*
229          * 'index' is NOT available (ADD operation),
230          * insert 'index' to corresponding index list.
231          */
232         switch (pb_type) {
233         case PB_TYPE_FDN:
234                 private_info->used_index_fdn = g_slist_insert_sorted(
235                         private_info->used_index_fdn,
236                         (gpointer)req_index,
237                         __phonebook_compare_index);
238
239                 /* Update Phonebook list valid */
240                 if (private_info->used_index_fdn_valid != TRUE)
241                         private_info->used_index_fdn_valid = TRUE;
242         break;
243
244         case PB_TYPE_ADN:
245                 private_info->used_index_adn = g_slist_insert_sorted(
246                         private_info->used_index_adn,
247                         (gpointer)req_index,
248                         __phonebook_compare_index);
249
250                 /* Update Phonebook list valid */
251                 if (private_info->used_index_adn_valid != TRUE)
252                         private_info->used_index_adn_valid = TRUE;
253         break;
254
255         case PB_TYPE_SDN:
256                 private_info->used_index_sdn = g_slist_insert_sorted(
257                         private_info->used_index_sdn,
258                         (gpointer)req_index,
259                         __phonebook_compare_index);
260
261                 /* Update Phonebook list valid */
262                 if (private_info->used_index_sdn_valid != TRUE)
263                         private_info->used_index_sdn_valid = TRUE;
264         break;
265
266         case PB_TYPE_USIM:
267                 private_info->used_index_usim = g_slist_insert_sorted(
268                         private_info->used_index_usim,
269                         (gpointer)req_index,
270                         __phonebook_compare_index);
271
272                 /* Update Phonebook list valid */
273                 if (private_info->used_index_usim_valid != TRUE)
274                         private_info->used_index_usim_valid = TRUE;
275         break;
276
277         default:
278                 warn("Unexpected Phonebook type: [%d]", pb_type);
279                 g_assert_not_reached();
280         break;
281         }
282
283         return TRUE;
284 }
285
286 static gboolean __phonebook_get_index_list_by_type(CoreObject *co,
287         enum tel_phonebook_type pb_type, GSList **list)
288 {
289         PrivateInfo *private_info = tcore_object_ref_user_data(co);
290         g_assert(private_info != NULL);
291
292         switch (pb_type) {
293         case PB_TYPE_FDN:
294                 if (private_info->used_index_fdn_valid != TRUE)
295                         return FALSE;
296                 *list = private_info->used_index_fdn;
297         break;
298
299         case PB_TYPE_ADN:
300                 if (private_info->used_index_adn_valid != TRUE)
301                         return FALSE;
302                 *list = private_info->used_index_adn;
303         break;
304
305         case PB_TYPE_SDN:
306                 if (private_info->used_index_sdn_valid != TRUE)
307                         return FALSE;
308                 *list = private_info->used_index_sdn;
309         break;
310
311         case PB_TYPE_USIM:
312                 if (private_info->used_index_usim_valid != TRUE)
313                         return FALSE;
314                 *list = private_info->used_index_usim;
315         break;
316
317         default:
318                 warn("Unsupported Phonebook type");
319                 return FALSE;
320         break;
321         }
322
323         return TRUE;
324 }
325
326 static void __phonebook_check_used_index(CoreObject *co,
327         enum tel_phonebook_type pb_type, guint req_index, guint *used_index)
328 {
329         GSList *list = NULL;
330
331         /* Get used_index list by req_type */
332         if (__phonebook_get_index_list_by_type(co, pb_type, &list) != TRUE) {
333                 err("used_index list is NOT valid");
334                 *used_index = req_index;
335                 return;
336         }
337
338         /* Use first used_index in case req_index is not used */
339         *used_index = (guint)g_slist_nth_data(list, VAL_ZERO);
340         while (list) {
341                 if ((guint)list->data == req_index) {
342                         /*
343                          * req_index is equal to one of used_index
344                          */
345                         *used_index = req_index;
346                         return;
347                 }
348                 list = g_slist_next(list);
349         }
350 }
351
352 static void __on_resp_phonebook_get_support_list(TcorePending *p,
353         int data_len, const void *data, void *user_data)
354 {
355         const TcoreATResponse *resp = data;
356
357         CoreObject *co_phonebook = tcore_pending_ref_core_object(p);
358         TcorePlugin *plugin = tcore_object_ref_plugin(co_phonebook);
359
360         struct tnoti_phonebook_status noti_data = {0, };
361
362         dbg("Entry");
363
364         noti_data.b_init = FALSE;
365
366         if (resp && resp->success > VAL_ZERO) {
367                 const char *line;
368                 char *temp = NULL;
369                 char *ptr = NULL;
370
371                 GSList *tokens = NULL;
372                 char *pb_type = NULL;
373
374                 dbg("RESPONSE OK");
375
376                 if (resp->lines == NULL) {
377                         warn("Invalid notification");
378                         goto EXIT;
379                 }
380
381                 line = (const char *)resp->lines->data;
382                 tokens = tcore_at_tok_new(line);
383                 if (g_slist_length(tokens) < VAL_ONE) {
384                         warn("Invalid notification - 'number' of tokens: [%d]",
385                                 g_slist_length(tokens));
386
387                         /* Free resources */
388                         tcore_at_tok_free(tokens);
389
390                         goto EXIT;
391                 }
392
393                 temp = (char *)g_slist_nth_data(tokens, VAL_ZERO);
394                 pb_type = strtok_r(temp, "(,)", &ptr);
395
396                 while (pb_type != NULL) {
397                         temp =  tcore_at_tok_extract(pb_type);
398                         dbg("pbtype %s", temp);
399
400                         if (VAL_ZERO == g_strcmp0(temp, "FD")) {
401                                 dbg("SIM fixed-dialing Phonebook");
402                                 noti_data.support_list.b_fdn = TRUE;
403                         } else if (VAL_ZERO == g_strcmp0(temp, "SN")) {
404                                 dbg("Service Dialing Number");
405                                 noti_data.support_list.b_sdn = TRUE;
406                         } else if (VAL_ZERO == g_strcmp0(temp, "SM")) {
407                                 CoreObject *co_sim = NULL;
408                                 enum tel_sim_type sim_type = SIM_TYPE_UNKNOWN;
409
410                                 /* Fecth SIM type */
411                                 co_sim = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM);
412                                 if (co_sim == NULL) {
413                                         err("SIM Core object is NULL");
414
415                                         /* Free resources */
416                                         tcore_at_tok_free(tokens);
417                                         g_free(temp);
418
419                                         goto EXIT;
420                                 }
421
422                                 sim_type = tcore_sim_get_type(co_sim);
423                                 dbg("SIM type: [%d]", sim_type);
424                                 if (sim_type == SIM_TYPE_USIM) {        /* 3G SIM */
425                                         noti_data.support_list.b_usim = TRUE;
426                                         dbg("3G SIM - USIM Phonebook");
427                                 } else {        /* 2G SIM */
428                                         noti_data.support_list.b_adn = TRUE;
429                                         dbg("2G SIM - ADN Phonebook");
430                                 }
431                         } else if (VAL_ZERO == g_strcmp0(temp, "LD")) {
432                                 dbg("SIM/UICC - last-dialling-phonebook");
433                         } else if (VAL_ZERO == g_strcmp0(temp, "ON")) {
434                                 dbg("SIM (or MT) own numbers (MSISDNs) list");
435                         } else if (VAL_ZERO == g_strcmp0(temp, "BL")) {
436                                 dbg("Blacklist phonebook");
437                         } else if (VAL_ZERO == g_strcmp0(temp, "EC")) {
438                                 dbg("SIM emergency-call-codes phonebook");
439                         } else if (VAL_ZERO == g_strcmp0(temp, "AP")) {
440                                 dbg("Selected application phonebook");
441                         } else if (VAL_ZERO == g_strcmp0(temp, "BN")) {
442                                 dbg("SIM barred-dialling-number");
443                         }
444
445                         pb_type = strtok_r(NULL, "(,)", &ptr);
446
447                         g_free(temp);
448                 }
449
450                 /* Free resources */
451                 tcore_at_tok_free(tokens);
452
453                 dbg("FDN: [%s] ADN: [%s] SDN: [%s] USIM: [%s]",
454                         noti_data.support_list.b_fdn ? "TRUE" : "FALSE",
455                         noti_data.support_list.b_adn ? "TRUE" : "FALSE",
456                         noti_data.support_list.b_sdn ? "TRUE" : "FALSE",
457                         noti_data.support_list.b_usim ? "TRUE" : "FALSE");
458
459                 /* Phonebook initialized */
460                 noti_data.b_init = TRUE;
461
462                 /* Update states */
463                 tcore_phonebook_set_support_list(co_phonebook, &noti_data.support_list);
464                 tcore_phonebook_set_status(co_phonebook, noti_data.b_init);
465         } else {
466                 dbg("RESPONSE NOK");
467
468                 /* Update state */
469                 tcore_phonebook_set_status(co_phonebook, noti_data.b_init);
470         }
471
472 EXIT:
473         /*
474          * Send notification
475          *
476          * Phonebook status (TNOTI_PHONEBOOK_STATUS)
477          */
478         tcore_server_send_notification(tcore_plugin_ref_server(plugin),
479                 co_phonebook,
480                 TNOTI_PHONEBOOK_STATUS,
481                 sizeof(struct tnoti_phonebook_status), &noti_data);
482
483         dbg("Exit");
484 }
485
486 /*
487  * Operation - get_support_list
488  *
489  * Request -
490  * AT-Command: AT+CPBS=?
491  *
492  * Response -
493  * Success: (Single line)
494  *      (list of supported <storage>s)
495  *      OK
496  * Failure:
497  *      +CME ERROR: <error>
498  */
499 static void __phonebook_get_support_list(CoreObject *co_phonebook)
500 {
501         TReturn ret;
502
503         dbg("Entry");
504
505         if (!co_phonebook) {
506                 err("Core object is NULL");
507                 return;
508         }
509
510         ret = tcore_prepare_and_send_at_request(co_phonebook,
511                 "AT+CPBS=?", "+CPBS",
512                 TCORE_AT_SINGLELINE,
513                 NULL,
514                 __on_resp_phonebook_get_support_list, NULL,
515                 NULL, NULL,
516                 0, NULL, NULL);
517         dbg("ret: [0x%x]", ret);
518 }
519
520 static void __on_resp_phonebook_get_used_index(TcorePending *p,
521         int data_len, const void *data, void *user_data)
522 {
523         const struct tcore_at_response *at_resp = data;
524         CoreObject *co = tcore_pending_ref_core_object(p);
525
526         g_assert(at_resp != NULL);
527
528         dbg("Entry");
529
530         if (at_resp->success > VAL_ZERO) {
531                 dbg("Response OK");
532
533                 if (at_resp->lines == NULL) {
534                         err("at_resp->lines is NULL");
535                 } else {
536                         GSList *lines = at_resp->lines;
537                         enum tel_phonebook_type req_pb_type;
538                         GSList **list = NULL;
539                         PrivateInfo *private_info = tcore_object_ref_user_data(co);
540
541                         g_assert(private_info != NULL);
542
543                         req_pb_type = (enum tel_phonebook_type)GPOINTER_TO_INT(user_data);
544
545                         /* Select used_index_list by req_type */
546                         switch (req_pb_type) {
547                         case PB_TYPE_FDN:
548                                 list = &private_info->used_index_fdn;
549                                 private_info->used_index_fdn_valid = TRUE;
550                         break;
551
552                         case PB_TYPE_ADN:
553                                 list = &private_info->used_index_adn;
554                                 private_info->used_index_adn_valid = TRUE;
555                         break;
556
557                         case PB_TYPE_SDN:
558                                 list = &private_info->used_index_sdn;
559                                 private_info->used_index_sdn_valid = TRUE;
560                         break;
561
562                         case PB_TYPE_USIM:
563                                 list = &private_info->used_index_usim;
564                                 private_info->used_index_usim_valid = TRUE;
565                         break;
566
567                         default:
568                                 warn("Unsupported phonebook: [%d]", req_pb_type);
569                                 return;
570                         }
571
572                         while (lines) {
573                                 const gchar *line = lines->data;
574                                 GSList *tokens = NULL;
575                                 gchar *temp;
576
577                                 dbg("Line: [%s]", line);
578
579                                 tokens = tcore_at_tok_new(line);
580                                 if (tokens == NULL) {
581                                         err("tokens is NULL");
582                                         return;
583                                 }
584
585                                 /* Get only used_index */
586                                 temp = g_slist_nth_data(tokens, VAL_ZERO);
587                                 if (temp) {
588                                         /* Insert used_index in PrivateInfo sorted in ascending */
589                                         *list = g_slist_insert_sorted(*list,
590                                                 (gpointer)atoi(temp),
591                                                 __phonebook_compare_index);
592                                 }
593                                 tcore_at_tok_free(tokens);
594
595                                 /* Get next lines */
596                                 lines = g_slist_next(lines);
597                         }
598
599                         dbg("pb_type: [%d], used_index Length: [%d]",
600                                 req_pb_type, g_slist_length(*list));
601                 }
602         } else {
603                 err("Response NOK");
604         }
605 }
606
607 static void __phonebook_get_used_index(CoreObject *co,
608         enum tel_phonebook_type pb_type, guint max_index)
609 {
610         gchar *at_cmd;
611         TReturn ret;
612
613         dbg("Entry");
614
615         /* AT-Command */
616         at_cmd = g_strdup_printf("AT+CPBR=1,%d", max_index);
617
618         /* Send Request to Modem */
619         ret = tcore_prepare_and_send_at_request(co,
620                 at_cmd, "+CPBR",
621                 TCORE_AT_MULTILINE,
622                 NULL,
623                 __on_resp_phonebook_get_used_index, GINT_TO_POINTER(pb_type),
624                 NULL, NULL,
625                 0, NULL, NULL);
626         dbg("ret: [0x%x]", ret);
627
628         /* Free resources */
629         g_free(at_cmd);
630 }
631
632 /******************************************************************************
633  * Phonebook Response functions
634  *****************************************************************************/
635 static void on_resp_get_count(TcorePending *p,
636         int data_len, const void *data, void *user_data)
637 {
638         const struct treq_phonebook_get_count *req_data = NULL;
639         struct tresp_phonebook_get_count resp_get_count;
640         const TcoreATResponse *resp = data;
641         UserRequest *ur = NULL;
642
643         dbg("Entry");
644
645         ur = tcore_pending_ref_user_request(p);
646         if (!ur) {
647                 dbg("ur is NULL");
648                 return;
649         }
650
651         req_data = (const struct treq_phonebook_get_count *)tcore_user_request_ref_data(ur, NULL);
652
653         memset(&resp_get_count, 0x00, sizeof(struct tresp_phonebook_get_count));
654         resp_get_count.result = PB_FAIL;
655         resp_get_count.type = req_data->phonebook_type;
656
657         if (resp && resp->success > VAL_ZERO) {
658                 PrivateInfo *private_info;
659                 CoreObject *co = tcore_pending_ref_core_object(p);
660                 enum tel_phonebook_type pb_type;
661
662                 GSList *tokens = NULL;
663                 char *temp = NULL;
664
665                 dbg("RESPONSE OK");
666
667                 if (resp->lines == NULL) {
668                         err("invalid message");
669                         goto EXIT;
670                 }
671
672                 temp = (char *)resp->lines->data;
673                 tokens = tcore_at_tok_new(temp);
674                 if (g_slist_length(tokens) < VAL_THREE) {
675                         /*
676                          * No of tokens must be three.
677                          * We cannot proceed without used and total count.
678                          */
679                         err("Invalid response - 'number' of tokens: [%d]", g_slist_length(tokens));
680
681                         /* Free resources */
682                         tcore_at_tok_free(tokens);
683
684                         goto EXIT;
685                 }
686
687                 resp_get_count.result = PB_SUCCESS;
688
689                 /* Fetch <used> */
690                 temp = g_slist_nth_data(tokens, VAL_ONE);
691                 if (temp)
692                         resp_get_count.used_count = atoi(temp);
693
694                 /* Fetch <total> */
695                 temp = g_slist_nth_data(tokens, VAL_TWO);
696                 if (temp)
697                         resp_get_count.total_count = atoi(temp);
698
699                 dbg("Used count [%d] Total count: [%d]", resp_get_count.used_count, resp_get_count.total_count);
700
701                 /* Free resources */
702                 tcore_at_tok_free(tokens);
703
704                 pb_type = resp_get_count.type;
705
706                 /* Updated selected Phonebook type */
707                 tcore_phonebook_set_selected_type(co, pb_type);
708
709                 /*
710                  * Cache 'used_index' by req_type if valid used_index is NOT TRUE.
711                  */
712                 private_info = tcore_object_ref_user_data(co);
713                 if ((pb_type == PB_TYPE_FDN && private_info->used_index_fdn_valid == FALSE)
714                                 || (pb_type == PB_TYPE_ADN && private_info->used_index_adn_valid == FALSE)
715                                 || (pb_type == PB_TYPE_SDN && private_info->used_index_sdn_valid == FALSE)
716                                 || (pb_type == PB_TYPE_USIM && private_info->used_index_usim_valid == FALSE)) {
717                         /* Cache 'used' index list */
718                         __phonebook_get_used_index(co, pb_type, resp_get_count.total_count);
719                 }
720         } else {
721                 dbg("RESPONSE NOK");
722         }
723 EXIT:
724         /* Send Response */
725         tcore_user_request_send_response(ur,
726                 TRESP_PHONEBOOK_GETCOUNT,
727                 sizeof(struct tresp_phonebook_get_count), &resp_get_count);
728
729         dbg("Exit");
730 }
731
732 static void on_resp_get_info(TcorePending *p,
733         int data_len, const void *data, void *user_data)
734 {
735         const struct treq_phonebook_get_info *req_data = NULL;
736         struct tresp_phonebook_get_info resp_get_info;
737         const TcoreATResponse *resp = data;
738         UserRequest *ur = NULL;
739
740         dbg("Entry");
741
742         ur = tcore_pending_ref_user_request(p);
743         if (!ur) {
744                 dbg("ur is NULL");
745                 return;
746         }
747
748         req_data = (const struct treq_phonebook_get_info *)tcore_user_request_ref_data(ur, NULL);
749
750         memset(&resp_get_info, 0x00, sizeof(struct tresp_phonebook_get_info));
751
752         resp_get_info.result = PB_FAIL;
753         resp_get_info.type = req_data->phonebook_type;
754         dbg("Phonebook type: [%d]", resp_get_info.type);
755
756         if (resp && resp->success > VAL_ZERO) {
757                 PrivateInfo *private_info;
758                 CoreObject *co = tcore_pending_ref_core_object(p);
759                 enum tel_phonebook_type pb_type;
760
761                 GSList *tokens = NULL;
762                 const char *line;
763                 GSList *lines = resp->lines;
764                 gchar *temp;
765
766                 dbg("RESPONSE OK");
767
768                 if (resp->lines == NULL) {
769                         err("invalid message");
770                         goto EXIT;
771                 }
772
773                 /*
774                  * +CPBS: <storage>[,<used>][,total]
775                  */
776                 line = g_slist_nth_data(lines, VAL_ZERO);
777                 dbg("First Line: [%s]", line);
778                 tokens = tcore_at_tok_new(line);
779                 if (tokens == NULL) {
780                         err("invalid message");
781                         goto EXIT;
782                 }
783
784                 /* Fetch <used> */
785                 temp = g_slist_nth_data(tokens, VAL_ONE);
786                 if (temp)
787                         resp_get_info.used_count =  atoi(temp);
788
789                 /* Fetch <total> */
790                 temp = g_slist_nth_data(tokens, VAL_TWO);
791                 if (temp)
792                         resp_get_info.index_max = atoi(temp);
793
794                 resp_get_info.index_min = 1;
795
796                 dbg("Used count: [%d] Total count (index_max): [%d] " \
797                         "Minimum count (index_min): [%d]",
798                         resp_get_info.used_count, resp_get_info.index_max,
799                         resp_get_info.index_min);
800
801                 /* Free resources */
802                 tcore_at_tok_free(tokens);
803
804                 resp_get_info.result = PB_SUCCESS;
805
806                 /*
807                  * +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>]
808                  */
809                 line = g_slist_nth_data(lines, VAL_ONE);
810                 dbg("Second Line: [%s]", line);
811                 tokens = tcore_at_tok_new(line);
812                 if (tokens == NULL) {
813                         err("invalid message");
814                         goto EXIT;
815                 }
816
817                 /* Fetch <nlength> */
818                 temp = g_slist_nth_data(tokens, VAL_ONE);
819                 if (temp)
820                         resp_get_info.number_length_max = atoi(temp);
821
822                 /* Fetch <tlength> */
823                 temp = g_slist_nth_data(tokens, VAL_ONE);
824                 if (temp)
825                         resp_get_info.text_length_max = atoi(temp);
826
827                 dbg("Number length: [%d] Test length: [%d]",
828                         resp_get_info.number_length_max, resp_get_info.text_length_max);
829
830                 /* Free resources */
831                 tcore_at_tok_free(tokens);
832
833                 pb_type = resp_get_info.type;
834
835                 /* Updated selected Phonebook type */
836                 tcore_phonebook_set_selected_type(co, pb_type);
837
838                 /*
839                  * Cache 'used_index' by req_type if valid used_index is NOT TRUE.
840                  */
841                 private_info = tcore_object_ref_user_data(co);
842                 if ((pb_type == PB_TYPE_FDN && private_info->used_index_fdn_valid == FALSE)
843                                 || (pb_type == PB_TYPE_ADN && private_info->used_index_adn_valid == FALSE)
844                                 || (pb_type == PB_TYPE_SDN && private_info->used_index_sdn_valid == FALSE)
845                                 || (pb_type == PB_TYPE_USIM && private_info->used_index_usim_valid == FALSE)) {
846                         /* Cache 'used' index list */
847                         __phonebook_get_used_index(co, pb_type, resp_get_info.index_max);
848                 }
849         } else {
850                 dbg("RESPONSE NOK");
851         }
852
853 EXIT:
854         /* Send Response */
855         tcore_user_request_send_response(ur,
856                 TRESP_PHONEBOOK_GETMETAINFO,
857                 sizeof(struct tresp_phonebook_get_info), &resp_get_info);
858
859         dbg("Exit");
860 }
861
862 static void on_resp_get_usim_info(TcorePending *p,
863         int data_len, const void *data, void *user_data)
864 {
865         struct tresp_phonebook_get_usim_info res_get_usim_info;
866         const TcoreATResponse *resp = data;
867         UserRequest *ur = NULL;
868
869         dbg("Entry");
870
871         ur = tcore_pending_ref_user_request(p);
872         if (!ur) {
873                 dbg("error - current ur is NULL");
874                 return;
875         }
876
877         memset(&res_get_usim_info, 0x00, sizeof(struct tresp_phonebook_get_usim_info));
878         res_get_usim_info.result = PB_FAIL;
879
880         if (resp && resp->success > VAL_ZERO) {
881                 PrivateInfo *private_info;
882                 CoreObject *co = tcore_pending_ref_core_object(p);
883
884                 GSList *tokens = NULL;
885                 const char *line;
886                 GSList *lines = resp->lines;
887                 int used = 0, total = 0;
888                 int nlen = 0, tlen = 0, glen = 0, slen = 0, elen = 0;
889                 enum tel_phonebook_field_type phonebook_field_type;
890                 int field_type;
891                 gchar *temp;
892
893                 dbg("RESPONSE OK");
894
895                 if (resp->lines == NULL) {
896                         err("invalid message");
897                         goto EXIT;
898                 }
899
900                 /*
901                  * +CPBS: <storage>[,<used>][,total]
902                  */
903                 line = g_slist_nth_data(lines, VAL_ZERO);
904                 dbg("First Line: [%s]", line);
905                 tokens = tcore_at_tok_new(line);
906                 if (tokens == NULL) {
907                         err("invalid message");
908                         goto EXIT;
909                 }
910
911                 /* Fetch <used> */
912                 temp = g_slist_nth_data(tokens, VAL_ONE);
913                 if (temp)
914                         used =  atoi(temp);
915
916                 /* Fetch <total> */
917                 temp = g_slist_nth_data(tokens, VAL_TWO);
918                 if (temp)
919                         total = atoi(temp);
920
921                 dbg("used_count %d index_max %d", used, total);
922
923                 /* Free resources */
924                 tcore_at_tok_free(tokens);
925
926                 /*
927                  * +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>]
928                  */
929                 line = g_slist_nth_data(lines, VAL_ONE);
930                 dbg("Second Line: [%s]", line);
931                 tokens = tcore_at_tok_new(line);
932                 if (tokens == NULL) {
933                         err("invalid message");
934                         goto EXIT;
935                 }
936
937                 /* Fetch <nlength> */
938                 temp = g_slist_nth_data(tokens, VAL_ZERO);
939                 if (temp)
940                         nlen = atoi(temp);
941
942                 /* Fetch <tlength> */
943                 temp = g_slist_nth_data(tokens, VAL_ONE);
944                 if (temp)
945                         tlen = atoi(temp);
946
947                 /* Fetch <glength> */
948                 temp = g_slist_nth_data(tokens, VAL_TWO);
949                 if (temp)
950                         glen = atoi(temp);
951
952                 /* Fetch <slength> */
953                 temp = g_slist_nth_data(tokens, VAL_THREE);
954                 if (temp)
955                         slen = atoi(temp);
956
957                 /* Fetch <elength> */
958                 temp = g_slist_nth_data(tokens, VAL_FOUR);
959                 if (temp)
960                         elen = atoi(temp);
961
962                 dbg("Length - Number: [%d] Test: [%d] Group: [%d] " \
963                         "Second name: [%d] e-mail: [%d]",
964                         nlen, tlen, glen, slen, elen);
965
966                 for (field_type = 1; field_type <= IMC_PB_INFO_LENGTH; field_type++) {
967                         phonebook_field_type = __phonebook_convert_field_type(field_type);
968
969                         res_get_usim_info.field_list[field_type-1].field = phonebook_field_type;
970                         res_get_usim_info.field_list[field_type-1].used_count = used;
971                         res_get_usim_info.field_list[field_type-1].index_max = total;
972
973                         switch (phonebook_field_type) {
974                         case PB_FIELD_NUMBER:
975                                 res_get_usim_info.field_list[field_type-1].text_max = nlen;
976                         break;
977
978                         case PB_FIELD_NAME:
979                                 res_get_usim_info.field_list[field_type-1].text_max = tlen;
980                         break;
981
982                         case PB_FIELD_GRP:
983                                 res_get_usim_info.field_list[field_type-1].text_max = glen;
984                         break;
985
986                         case PB_FIELD_SNE:
987                                 res_get_usim_info.field_list[field_type-1].text_max = slen;
988                         break;
989
990                         case PB_FIELD_EMAIL1:
991                                 res_get_usim_info.field_list[field_type-1].text_max = elen;
992                         break;
993
994                         default:
995                                 warn("Unsupported Phonebook field type: [%d]", phonebook_field_type);
996                         break;
997                         }
998                 }
999
1000                 res_get_usim_info.field_count = IMC_PB_INFO_LENGTH;
1001                 res_get_usim_info.result = PB_SUCCESS;
1002
1003                 /* Free resources */
1004                 tcore_at_tok_free(tokens);
1005
1006                 /* Updated selected Phonebook type */
1007                 tcore_phonebook_set_selected_type(co, PB_TYPE_USIM);
1008
1009                 /*
1010                  * Cache 'used_index' for PB_TYPE_USIM if valid used_index is NOT TRUE.
1011                  */
1012                 private_info = tcore_object_ref_user_data(co);
1013                 if (private_info->used_index_usim_valid == FALSE) {
1014                         /* Cache 'used' index list */
1015                         __phonebook_get_used_index(co, PB_TYPE_USIM, total);
1016                 }
1017         }
1018
1019 EXIT:
1020         /* Send Response */
1021         tcore_user_request_send_response(ur,
1022                 TRESP_PHONEBOOK_GETUSIMINFO,
1023                 sizeof(struct tresp_phonebook_get_usim_info), &res_get_usim_info);
1024         dbg("Exit");
1025 }
1026
1027 static void on_resp_read_record(TcorePending *p,
1028         int data_len, const void *data, void *user_data)
1029 {
1030         const struct treq_phonebook_read_record *req_data = NULL;
1031         struct tresp_phonebook_read_record resp_read_record;
1032         const TcoreATResponse *resp = data;
1033         UserRequest *ur = NULL;
1034
1035         dbg("Entry");
1036
1037         ur = tcore_pending_ref_user_request(p);
1038         if (!ur) {
1039                 dbg("error - current ur is NULL");
1040                 return;
1041         }
1042
1043         req_data = tcore_user_request_ref_data(ur, NULL);
1044
1045         memset(&resp_read_record, 0x00, sizeof(struct tresp_phonebook_read_record));
1046
1047         resp_read_record.result = PB_FAIL;
1048         resp_read_record.phonebook_type = req_data->phonebook_type;
1049
1050         if (resp && resp->success > VAL_ZERO) {
1051                 CoreObject *co = tcore_pending_ref_core_object(p);
1052                 GSList *list = NULL;
1053
1054                 GSList *tokens = NULL;
1055                 const char *line;
1056
1057                 int num_plan = VAL_ZERO;
1058                 char *number = NULL, *name = NULL, *additional_number = NULL;
1059                 char *sne = NULL, *email = NULL;
1060                 char *temp = NULL;
1061
1062                 dbg("RESPONSE OK");
1063
1064                 if (resp->lines == NULL) {
1065                         err("invalid message");
1066                         goto EXIT;
1067                 }
1068
1069                 /*
1070                  * +CPBR: <index>,<number>,<type>,<text>[,<hidden>][,<group>]
1071                  *      [,<adnumber>][,<adtype>][,<secondtext>][,<email>]]
1072                  */
1073                 line = (const char *)resp->lines->data;
1074                 tokens = tcore_at_tok_new(line);
1075                 if (g_slist_length(tokens) < VAL_ONE) {
1076                         err("invalid message");
1077                         goto EXIT;
1078                 }
1079
1080                 /* Fetch <index> */
1081                 temp = g_slist_nth_data(tokens, VAL_ZERO);
1082                 if (temp == NULL) {
1083                         err("No index");
1084                         goto EXIT;
1085                 }
1086                 resp_read_record.index = atoi(temp);
1087
1088                 /* Fetch <number> */
1089                 temp = g_slist_nth_data(tokens, VAL_ONE);
1090                 if (temp == NULL) {
1091                         err("No number");
1092                         goto EXIT;
1093                 }
1094                 number = tcore_at_tok_extract(temp);
1095                 g_strlcpy((char *)resp_read_record.number,
1096                         (const gchar *)number, PHONEBOOK_NUMBER_BYTE_MAX+1);
1097                 g_free(number);
1098
1099                 /* Fetch <type> */
1100                 temp = g_slist_nth_data(tokens, VAL_TWO);
1101                 if (temp == NULL) {
1102                         err("No type");
1103                         goto EXIT;
1104                 }
1105                 num_plan = atoi(temp);
1106                 resp_read_record.ton = __phonebook_find_num_plan(num_plan);
1107
1108                 /* Fetch <text> */
1109                 temp = g_slist_nth_data(tokens, VAL_THREE);
1110                 if (temp == NULL) {
1111                         err("No text");
1112                         goto EXIT;
1113                 }
1114                 name = tcore_at_tok_extract(temp);
1115                 if (name) {
1116                         g_strlcpy((char *)resp_read_record.name,
1117                                 (const gchar *)name, PHONEBOOK_NAME_BYTE_MAX+1);
1118                         resp_read_record.name_len = strlen((const char *)resp_read_record.name);
1119                         resp_read_record.dcs = PB_TEXT_ASCII;
1120                         g_free(name);
1121                 }
1122
1123                 /* All 'mandatory' fields are extracted */
1124                 resp_read_record.result = PB_SUCCESS;
1125
1126                 /* Updated selected Phonebook type */
1127                 tcore_phonebook_set_selected_type(co, req_data->phonebook_type);
1128
1129                 /* Get used_index list by req_type */
1130                 if (__phonebook_get_index_list_by_type(co,
1131                                 req_data->phonebook_type, &list) == TRUE) {
1132                         while (list) {
1133                                 if ((guint)list->data == resp_read_record.index) {
1134                                         if ((list = g_slist_next(list)) != NULL) {
1135                                                 /* If exist, set next_index */
1136                                                 resp_read_record.next_index = (guint)list->data;
1137                                                 dbg("next_index is [%u]", resp_read_record.next_index);
1138                                         } else {
1139                                                 /* read_record.index is the end of used_index */
1140                                                 resp_read_record.next_index = 0;
1141                                                 dbg("End of used_index");
1142                                         }
1143                                         break;
1144                                 }
1145                                 list = g_slist_next(list);
1146                         }
1147                 } else {
1148                         /* No PrivateInfo */
1149                         resp_read_record.next_index = 0;
1150                 }
1151
1152                 /* Fetch <hidden> */
1153                 temp = g_slist_nth_data(tokens, VAL_FOUR);
1154                 if (temp)
1155                         dbg("Phonebook entry is hidden");
1156
1157                 /* Fetch <adnumber> */
1158                 temp = g_slist_nth_data(tokens, VAL_SIX);
1159                 additional_number = tcore_at_tok_extract(temp);
1160                 if (additional_number) {
1161                         g_strlcpy((char *)resp_read_record.anr1,
1162                                 (const gchar *)additional_number, PHONEBOOK_NUMBER_BYTE_MAX+1);
1163                         g_free(additional_number);
1164                 }
1165
1166                 /* Fetch <adtype> */
1167                 temp = g_slist_nth_data(tokens, VAL_SEVEN);
1168                 name = tcore_at_tok_extract(temp);
1169                 if (temp) {
1170                         num_plan = atoi(temp);
1171                         resp_read_record.anr1_ton = __phonebook_find_num_plan(num_plan);
1172                 }
1173
1174                 /* Fetch <secondtext> */
1175                 temp = g_slist_nth_data(tokens, VAL_EIGHT);
1176                 if (temp == NULL) {
1177                         err("No text");
1178                         goto EXIT;
1179                 }
1180                 sne = tcore_at_tok_extract(temp);
1181                 if (sne) {
1182                         g_strlcpy((char *)resp_read_record.sne,
1183                                 (const gchar *)sne, PHONEBOOK_NAME_BYTE_MAX+1);
1184                         resp_read_record.sne_len = strlen((const char *)resp_read_record.sne);
1185                         resp_read_record.sne_dcs = PB_TEXT_ASCII;
1186                         g_free(sne);
1187                 }
1188
1189                 /* Fetch <email> */
1190                 temp = g_slist_nth_data(tokens, VAL_NINE);
1191                 if (temp == NULL) {
1192                         err("No text");
1193                         goto EXIT;
1194                 }
1195                 email = tcore_at_tok_extract(temp);
1196                 if (email) {
1197                         g_strlcpy((char *)resp_read_record.email1,
1198                                 (const gchar *)email, PHONEBOOK_EMAIL_BYTE_MAX+1);
1199                         resp_read_record.email1_len = strlen((const char *)resp_read_record.email1);
1200                         g_free(email);
1201                 }
1202
1203 EXIT:
1204                 /* Free resources */
1205                 tcore_at_tok_free(tokens);
1206         } else {
1207                 dbg("RESPONSE NOK");
1208         }
1209
1210         /* Send Response */
1211         tcore_user_request_send_response(ur,
1212                 TRESP_PHONEBOOK_READRECORD,
1213                 sizeof(struct tresp_phonebook_read_record), &resp_read_record);
1214
1215         dbg("Exit");
1216 }
1217
1218 static void on_resp_update_record(TcorePending *p,
1219         int data_len, const void *data, void *user_data)
1220 {
1221         const TcoreATResponse *resp = data;
1222         UserRequest *ur = NULL;
1223         struct tresp_phonebook_update_record resp_update_record;
1224
1225         dbg("Entry");
1226
1227         ur = tcore_pending_ref_user_request(p);
1228
1229         if (resp && resp->success > VAL_ZERO) {
1230                 const struct treq_phonebook_update_record *req_data = NULL;
1231                 CoreObject *co = tcore_pending_ref_core_object(p);
1232
1233                 dbg("RESPONSE OK");
1234
1235                 resp_update_record.result = PB_SUCCESS;
1236
1237                 req_data = tcore_user_request_ref_data(ur, NULL);
1238
1239                 /* Updated selected Phonebook type */
1240                 tcore_phonebook_set_selected_type(co, req_data->phonebook_type);
1241
1242                 /*
1243                  * Need to update the corresponding index list.
1244                  *
1245                  * in case 'not available' (ADD operation) - ADD index
1246                  * in case 'available' (UPDATE operation) - NO change
1247                  */
1248                 __phonebook_update_index_list_by_type(co,
1249                         req_data->phonebook_type, req_data->index);
1250         } else {
1251                 dbg("RESPONSE NOK");
1252                 resp_update_record.result = PB_FAIL;
1253         }
1254
1255         if (ur) {
1256                 /* Send Response */
1257                 tcore_user_request_send_response(ur,
1258                         TRESP_PHONEBOOK_UPDATERECORD,
1259                         sizeof(struct tresp_phonebook_update_record), &resp_update_record);
1260         } else {
1261                 err("ur is NULL");
1262         }
1263
1264         dbg("Exit");
1265 }
1266
1267 static void on_resp_delete_record(TcorePending *p,
1268         int data_len, const void *data, void *user_data)
1269 {
1270         const TcoreATResponse *resp = data;
1271         UserRequest *ur = NULL;
1272         struct tresp_phonebook_delete_record resp_delete_record;
1273
1274         dbg("Entry");
1275
1276         ur = tcore_pending_ref_user_request(p);
1277
1278         if (resp && resp->success > VAL_ZERO) {
1279                 const struct treq_phonebook_delete_record *req_data = NULL;
1280                 CoreObject *co = tcore_pending_ref_core_object(p);
1281                 GSList *list = NULL;
1282
1283                 dbg("RESPONSE OK");
1284
1285                 resp_delete_record.result = PB_SUCCESS;
1286
1287                 req_data = tcore_user_request_ref_data(ur, NULL);
1288
1289                 /* Updated selected Phonebook type */
1290                 tcore_phonebook_set_selected_type(co, req_data->phonebook_type);
1291
1292                 /* Get used_index list by req_type */
1293                 if (__phonebook_get_index_list_by_type(co,
1294                                 req_data->phonebook_type, &list) != TRUE) {
1295                         err("used_index list is NOT valid");
1296                 } else {
1297                         const int del_index = (const int)req_data->index;
1298                         list = g_slist_remove(list, (gconstpointer)del_index);
1299                         dbg("Remove index: [%u] list: [0x%x]", req_data->index, list);
1300                 }
1301         } else {
1302                 dbg("RESPONSE NOK");
1303                 resp_delete_record.result = PB_FAIL;
1304         }
1305
1306         if (ur)
1307                 tcore_user_request_send_response(ur,
1308                         TRESP_PHONEBOOK_DELETERECORD,
1309                         sizeof(struct tresp_phonebook_delete_record), &resp_delete_record);
1310         else
1311                 err("ur is NULL");
1312
1313         dbg("Exit");
1314 }
1315
1316 /******************************************************************************
1317  * Phonebook Request functions
1318  *****************************************************************************/
1319 /*
1320  * Operation - get_count
1321  *
1322  * Request -
1323  * AT-Command: AT+CPBS?
1324  *
1325  * Response -
1326  * Success: (Single line)
1327  *      +CPBS: <storage>[,<used>][,total]
1328  *      OK
1329  * where,
1330  * <storage> Phonebook storage type
1331  * <used> Number of records 'used'
1332  * <total> 'total' number of records available
1333  *
1334  * Failure:
1335  *      +CME ERROR: <error>
1336  */
1337 static TReturn imc_get_count(CoreObject *co, UserRequest *ur)
1338 {
1339         struct treq_phonebook_get_count *req_data = NULL;
1340         gchar *at_cmd;
1341         gchar *set_pb_cmd;
1342
1343         TReturn ret = TCORE_RETURN_FAILURE;
1344
1345         dbg("Entry");
1346
1347         req_data = (struct treq_phonebook_get_count *)tcore_user_request_ref_data(ur, NULL);
1348
1349         /* Check whether pb_type is supported or not, and Select pb_type */
1350         if (__phonebook_check_and_select_type(co,
1351                         req_data->phonebook_type, &set_pb_cmd) != TRUE) {
1352                 warn("Requested phonebok type '%d' is NOT supported",
1353                         req_data->phonebook_type);
1354                 return ret;
1355         }
1356
1357         /* AT-Command */
1358         at_cmd = g_strdup_printf("%s+CPBS?", set_pb_cmd);
1359
1360         /* Send Request to Modem */
1361         ret = tcore_prepare_and_send_at_request(co,
1362                 at_cmd, "+CPBS",
1363                 TCORE_AT_SINGLELINE,
1364                 ur,
1365                 on_resp_get_count, NULL,
1366                 NULL, NULL,
1367                 0, NULL, NULL);
1368
1369         /* Free resources */
1370         g_free(at_cmd);
1371         g_free(set_pb_cmd);
1372
1373         return ret;
1374 }
1375
1376 /*
1377  * Operation - get_info
1378  *
1379  * Request -
1380  * AT-Command: AT+CPBS?;+CPBF=?
1381  *
1382  * Response -
1383  * Success: (Multi line)
1384  *      +CPBS: <storage>[,<used>][,total]
1385  *      +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>]
1386  *      OK
1387  * where,
1388  * <storage> Phonebook storage type
1389  * <used> Number of records 'used'
1390  * <total> 'total' number of records available
1391  * <nlength> Maximum length of field <number>
1392  * <tlength> Maximum length of field <text>
1393  * <glength> Maximum length of field <group>
1394  * <slength> Maximum length of field <secondtext>
1395  * <elength> Maximum length of field <email>
1396  *
1397  * Failure:
1398  *      +CME ERROR: <error>
1399  */
1400 static TReturn imc_get_info(CoreObject *co, UserRequest *ur)
1401 {
1402         struct treq_phonebook_get_info *req_data = NULL;
1403         gchar *at_cmd;
1404         gchar *set_pb_cmd;
1405
1406         TReturn ret = TCORE_RETURN_FAILURE;
1407
1408         dbg("Entry");
1409
1410         req_data = (struct treq_phonebook_get_info *)tcore_user_request_ref_data(ur, NULL);
1411
1412         /* Check whether pb_type is supported or not, and Select pb_type */
1413         if (__phonebook_check_and_select_type(co,
1414                         req_data->phonebook_type, &set_pb_cmd) != TRUE) {
1415                 warn("Requested phonebok type '%d' is NOT supported",
1416                         req_data->phonebook_type);
1417                 return ret;
1418         }
1419
1420         /* AT-Command */
1421         at_cmd = g_strdup_printf("%s+CPBS?;+CPBF=?", set_pb_cmd);
1422
1423         /* Send Request to Modem */
1424         ret = tcore_prepare_and_send_at_request(co,
1425                 at_cmd, "+CPB",
1426                 TCORE_AT_MULTILINE,
1427                 ur,
1428                 on_resp_get_info, NULL,
1429                 NULL, NULL,
1430                 0, NULL, NULL);
1431
1432         /* Free resources */
1433         g_free(at_cmd);
1434         g_free(set_pb_cmd);
1435
1436         return ret;
1437 }
1438
1439 /*
1440  * Operation - get_usim_info
1441  *
1442  * Request -
1443  * AT-Command: AT+CPBS?;+CPBF=?
1444  *
1445  * Response -
1446  * Success: (Multi line)
1447  *      +CPBS: <storage>[,<used>][,total]
1448  *      +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>]
1449  *      OK
1450  * where,
1451  * <storage> Phonebook storage type
1452  * <used> Number of records 'used'
1453  * <total> 'total' number of records available
1454  * <nlength> Maximum length of field <number>
1455  * <tlength> Maximum length of field <text>
1456  * <glength> Maximum length of field <group>
1457  * <slength> Maximum length of field <secondtext>
1458  * <elength> Maximum length of field <email>
1459  *
1460  * Failure:
1461  *      +CME ERROR: <error>
1462  */
1463 static TReturn imc_get_usim_info(CoreObject *co, UserRequest *ur)
1464 {
1465         gchar *at_cmd;
1466         gchar *set_pb_cmd;
1467
1468         TReturn ret = TCORE_RETURN_FAILURE;
1469
1470         dbg("Entry");
1471
1472         /* Check whether pb_type is supported or not, and Select pb_type */
1473         if (__phonebook_check_and_select_type(co, PB_TYPE_USIM, &set_pb_cmd) != TRUE) {
1474                 warn("Requested phonebok type '%d' is NOT supported", PB_TYPE_USIM);
1475                 return ret;
1476         }
1477
1478         /* AT-Command */
1479         at_cmd = g_strdup_printf("%s+CPBS?;+CPBF=?", set_pb_cmd);
1480
1481         /* Send Request to Modem */
1482         ret = tcore_prepare_and_send_at_request(co,
1483                 at_cmd, "+CPB",
1484                 TCORE_AT_MULTILINE,
1485                 ur,
1486                 on_resp_get_usim_info, NULL,
1487                 NULL, NULL,
1488                 0, NULL, NULL);
1489
1490         /* Free resources */
1491         g_free(at_cmd);
1492         g_free(set_pb_cmd);
1493
1494         return ret;
1495 }
1496
1497 /*
1498  * Operation - read_record
1499  *
1500  * Request -
1501  * AT-Command: AT+CPBR=<index>
1502  * where,
1503  * <index>
1504  * 1    Integer type values in range of location numbers of phonebook memory
1505  * ...
1506  *
1507  * Response -
1508  * Success: (Single line);
1509  *      +CPBR: <index>,<number>,<type>,<text>[,<hidden>][,<group>]
1510  *      [,<adnumber>][,<adtype>][,<secondtext>][,<email>]]
1511  *      OK
1512  * where,
1513  * <number> String type phone number of format <type>
1514  * <type> Type of address octet in integer format
1515  * <text> String type field of maximum length <tlength>
1516  * <hidden> Indicates if the entry is hidden or not â€“ only available,
1517  *              if a UICC with an active USIM application is present
1518  * 0    Phonebook entry not hidden
1519  * 1    Phonebook entry hidden
1520  * <group> String type field of maximum length <glength>
1521  * <adnumber> String type phone number of format <adtype>
1522  * <adtype> Type of address octet in integer format
1523  * <secondtext> String type field of maximum length <slength>
1524  * <email> String type field of maximum length <elength>
1525  *
1526  * Failure:
1527  *      +CME ERROR: <error>
1528  */
1529 static TReturn imc_read_record(CoreObject *co, UserRequest *ur)
1530 {
1531         const struct treq_phonebook_read_record *req_data = NULL;
1532         gchar *at_cmd;
1533         gchar *set_pb_cmd;
1534         guint used_index = 0;
1535
1536         TReturn ret = TCORE_RETURN_FAILURE;
1537
1538         dbg("Entry");
1539
1540         req_data = tcore_user_request_ref_data(ur, NULL);
1541
1542         /* Check whether pb_type is supported or not, and Select pb_type */
1543         if (__phonebook_check_and_select_type(co,
1544                         req_data->phonebook_type, &set_pb_cmd) != TRUE) {
1545                 warn("Requested phonebok type '%d' is NOT supported",
1546                         req_data->phonebook_type);
1547                 return ret;
1548         }
1549
1550         /* Check whether index is used or not */
1551         __phonebook_check_used_index(co,
1552                 req_data->phonebook_type, req_data->index, &used_index);
1553
1554         /* AT-Command */
1555         at_cmd = g_strdup_printf("%s+CPBR=%u", set_pb_cmd, used_index);
1556
1557         /* Send Request to Modem */
1558         ret = tcore_prepare_and_send_at_request(co,
1559                 at_cmd, "+CPBR",
1560                 TCORE_AT_SINGLELINE,
1561                 ur,
1562                 on_resp_read_record, NULL,
1563                 NULL, NULL,
1564                 0, NULL, NULL);
1565
1566         /* Free resources */
1567         g_free(at_cmd);
1568         g_free(set_pb_cmd);
1569
1570         return ret;
1571 }
1572
1573 /*
1574  * Operation - update_record
1575  *
1576  * Request -
1577  * AT-Command: AT+CPBW=[<index>][,<number>[,<type>[,<text>[,<group>[,<adnumber>
1578  *      [,<adtype>[,<secondtext>[,<email>[,<hidden>]]]]]]]]]
1579  * where,
1580  * ... same read_record Operation
1581  *
1582  * Response -
1583  * Success: (No Result)
1584  *      OK
1585  * Failure:
1586  *      +CME ERROR: <error>
1587  */
1588 static TReturn imc_update_record(CoreObject *co, UserRequest *ur)
1589 {
1590         const struct treq_phonebook_update_record *req_data = NULL;
1591         gchar *at_cmd;
1592         gchar *set_pb_cmd;
1593
1594         TReturn ret = TCORE_RETURN_FAILURE;
1595
1596         dbg("Entry");
1597
1598         req_data = tcore_user_request_ref_data(ur, NULL);
1599
1600         /* Check whether pb_type is supported or not, and Select pb_type */
1601         if (__phonebook_check_and_select_type(co,
1602                         req_data->phonebook_type, &set_pb_cmd) != TRUE) {
1603                 warn("Requested phonebok type '%d' is NOT supported",
1604                         req_data->phonebook_type);
1605                 return ret;
1606         }
1607
1608         /* Set AT-Command according pb_type */
1609         if (req_data->phonebook_type == PB_TYPE_USIM) {
1610                 at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",%d,\"%s\",,\"%s\",,\"%s\",\"%s\"",
1611                         set_pb_cmd, req_data->index,
1612                         req_data->number,
1613                         ((PB_TON_INTERNATIONAL == req_data->ton) ? IMC_TON_INTERNATIONAL : IMC_TON_UNKNOWN),
1614                         req_data->name, req_data->anr1,
1615                         req_data->sne, req_data->email1);
1616         } else {
1617                 at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\"",
1618                         set_pb_cmd, req_data->index,
1619                         req_data->number, req_data->name);
1620         }
1621
1622         /* Send Request to Modem */
1623         ret = tcore_prepare_and_send_at_request(co,
1624                 at_cmd, NULL,
1625                 TCORE_AT_NO_RESULT,
1626                 ur,
1627                 on_resp_update_record, NULL,
1628                 NULL, NULL,
1629                 0, NULL, NULL);
1630
1631         /* Free resources */
1632         g_free(at_cmd);
1633         g_free(set_pb_cmd);
1634
1635         return ret;
1636 }
1637
1638 /*
1639  * Operation - delete_record
1640  *
1641  * Request -
1642  * AT-Command: AT+CPBW=<index>
1643  * where,
1644  * <index>
1645  * 1    Integer type values in range of location numbers of phonebook memory
1646  * ...
1647  *
1648  * Response -
1649  * Success: (No Result)
1650  *      OK
1651  * Failure:
1652  *      +CME ERROR: <error>
1653  */
1654 static TReturn imc_delete_record(CoreObject *co, UserRequest *ur)
1655 {
1656         const struct treq_phonebook_delete_record *req_data;
1657         gchar *at_cmd;
1658         gchar *set_pb_cmd;
1659
1660         TReturn ret = TCORE_RETURN_FAILURE;
1661
1662         dbg("Entry");
1663
1664         req_data = tcore_user_request_ref_data(ur, NULL);
1665
1666         /* Check whether pb_type is supported or not, and Select pb_type */
1667         if (__phonebook_check_and_select_type(co,
1668                         req_data->phonebook_type, &set_pb_cmd) != TRUE) {
1669                 warn("Requested phonebok type '%d' is NOT supported",
1670                         req_data->phonebook_type);
1671                 return ret;
1672         }
1673
1674         /* AT-Command */
1675         at_cmd = g_strdup_printf("%s+CPBW=%u", set_pb_cmd, req_data->index);
1676
1677         /* Send Request to Modem */
1678         ret = tcore_prepare_and_send_at_request(co,
1679                 at_cmd, NULL,
1680                 TCORE_AT_NO_RESULT,
1681                 ur,
1682                 on_resp_delete_record, NULL,
1683                 NULL, NULL,
1684                 0, NULL, NULL);
1685
1686         /* Free resources */
1687         g_free(at_cmd);
1688         g_free(set_pb_cmd);
1689
1690         return ret;
1691 }
1692
1693 /******************************************************************************
1694  * Phonebook Notification function(s)
1695  *****************************************************************************/
1696 static gboolean on_noti_phonebook_status(CoreObject *co_phonebook,
1697         const void *event_info, void *user_data)
1698 {
1699         dbg("Received [+PBREADY]");
1700
1701         /*
1702          * Get supported list of Phonebook types
1703          */
1704         __phonebook_get_support_list(co_phonebook);
1705
1706         return TRUE;
1707 }
1708
1709 /* Phonebook operations */
1710 static struct tcore_phonebook_operations phonebook_ops = {
1711         .get_count = imc_get_count,
1712         .get_info = imc_get_info,
1713         .get_usim_info = imc_get_usim_info,
1714         .read_record = imc_read_record,
1715         .update_record = imc_update_record,
1716         .delete_record = imc_delete_record,
1717 };
1718
1719 gboolean imc_phonebook_init(TcorePlugin *cp, CoreObject *co_phonebook)
1720 {
1721         PrivateInfo *private_info;
1722
1723         dbg("Entry");
1724
1725         /* Set operations */
1726         tcore_phonebook_set_ops(co_phonebook, &phonebook_ops, TCORE_OPS_TYPE_CP);
1727
1728         /* Set PrivateInfo */
1729         private_info = g_malloc0(sizeof(PrivateInfo));
1730         tcore_object_link_user_data(co_phonebook, private_info);
1731
1732         /* Add Callbacks */
1733         tcore_object_add_callback(co_phonebook,
1734                 "+PBREADY",
1735                 on_noti_phonebook_status, co_phonebook);
1736
1737         dbg("Exit");
1738
1739         return TRUE;
1740 }
1741
1742 void imc_phonebook_exit(TcorePlugin *cp, CoreObject *co_phonebook)
1743 {
1744         PrivateInfo *private_info;
1745
1746         private_info = tcore_object_ref_user_data(co_phonebook);
1747         g_assert(private_info != NULL);
1748
1749         /* Free PrivateInfo */
1750         g_slist_free_full(private_info->used_index_fdn, g_free);
1751         g_slist_free_full(private_info->used_index_adn, g_free);
1752         g_slist_free_full(private_info->used_index_sdn, g_free);
1753         g_slist_free_full(private_info->used_index_usim, g_free);
1754         g_free(private_info);
1755
1756         /* Remove Callbacks */
1757         tcore_object_del_callback(co_phonebook,
1758                 "+PBREADY", on_noti_phonebook_status);
1759
1760         dbg("Exit");
1761 }