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