Added support for Cancel Network Search
[platform/core/telephony/tel-plugin-imc.git] / src / imc_phonebook.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33
34 #include <co_phonebook.h>
35 #include <co_sim.h>
36
37 #include "imc_phonebook.h"
38 #include "imc_common.h"
39
40 typedef struct {
41         GSList *used_index_fdn;
42         gboolean used_index_fdn_valid;
43
44         GSList *used_index_adn;
45         gboolean used_index_adn_valid;
46
47         GSList *used_index_sdn;
48         gboolean used_index_sdn_valid;
49
50         GSList *used_index_usim;
51         gboolean used_index_usim_valid;
52 } PrivateInfo;
53
54 static gboolean __imc_phonebook_get_sim_type(CoreObject *co_pb,
55                 TelSimCardType *sim_type)
56 {
57         TcorePlugin *plugin;
58         CoreObject *co_sim;
59         tcore_check_return_value_assert(co_pb != NULL, FALSE);
60         tcore_check_return_value_assert(sim_type != NULL, FALSE);
61
62         plugin = tcore_object_ref_plugin(co_pb);
63         co_sim = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM);
64         return tcore_sim_get_type(co_sim, sim_type);
65 }
66
67 static gboolean __imc_phonebook_get_pb_type_str(TelPbType pb_type,
68                 gchar **req_type_str)
69 {
70         tcore_check_return_value_assert(req_type_str != NULL, FALSE);
71
72         switch (pb_type) {
73         case TEL_PB_FDN:
74                 *req_type_str = g_strdup("FD");
75                 break;
76         case TEL_PB_ADN:
77         case TEL_PB_USIM:
78                 *req_type_str = g_strdup("SM");
79                 break;
80         case TEL_PB_SDN:
81                 *req_type_str = g_strdup("SN");
82                 break;
83         }
84
85         return TRUE;
86 }
87
88 static gboolean __imc_phonebook_check_and_select_type(CoreObject *co,
89                 TelPbType req_type, gchar **set_pb_cmd)
90 {
91         TelPbList *support_list;
92         TelPbType current_type;
93
94         /* Check whether pb_type is supported or not */
95         tcore_phonebook_get_support_list(co, &support_list);
96         if ((req_type == TEL_PB_FDN && support_list->fdn == FALSE)
97                         || (req_type == TEL_PB_ADN && support_list->adn == FALSE)
98                         || (req_type == TEL_PB_SDN && support_list->sdn == FALSE)
99                         || (req_type == TEL_PB_USIM && support_list->usim == FALSE)) {
100                 err("Not supported pb_type");
101                 g_free(support_list);
102                 return FALSE;
103         }
104         g_free(support_list);
105
106         /* Check Current type & Request type */
107         tcore_phonebook_get_selected_type(co, &current_type);
108         if (current_type != req_type) {
109                 gchar *req_type_str = NULL;
110                 __imc_phonebook_get_pb_type_str(req_type, &req_type_str);
111                 dbg("Add AT-Command to change [%s] Type", req_type_str);
112                 /* Select Phonebook type */
113                 *set_pb_cmd = g_strdup_printf("AT+CPBS=\"%s\";", req_type_str);
114         } else {
115                 *set_pb_cmd = g_strdup_printf("AT");
116         }
117
118         return TRUE;
119 }
120
121 static gboolean __imc_phonebook_get_index_list_by_type(CoreObject *co,
122                 TelPbType pb_type, GSList **list)
123 {
124         PrivateInfo *private_info = tcore_object_ref_user_data(co);
125         tcore_check_return_value_assert(private_info != NULL, FALSE);
126
127         switch (pb_type) {
128         case TEL_PB_FDN:
129                 if (private_info->used_index_fdn_valid != TRUE)
130                         return FALSE;
131                 *list = private_info->used_index_fdn;
132                 break;
133         case TEL_PB_ADN:
134                 if (private_info->used_index_adn_valid != TRUE)
135                         return FALSE;
136                 *list = private_info->used_index_adn;
137                 break;
138         case TEL_PB_SDN:
139                 if (private_info->used_index_sdn_valid != TRUE)
140                         return FALSE;
141                 *list = private_info->used_index_sdn;
142                 break;
143         case TEL_PB_USIM:
144                 if (private_info->used_index_usim_valid != TRUE)
145                         return FALSE;
146                 *list = private_info->used_index_usim;
147                 break;
148         }
149
150         return TRUE;
151 }
152
153 static void __imc_phonebook_check_used_index(CoreObject *co,
154                 TelPbType pb_type, guint req_index, guint *used_index)
155 {
156         GSList *list = NULL;
157
158         /* Get used_index list by req_type */
159         if (__imc_phonebook_get_index_list_by_type(co, pb_type, &list) != TRUE) {
160                 err("used_index list is NOT valid");
161                 *used_index = req_index;
162                 return;
163         }
164
165         /* Use first used_index in case req_index is not used */
166         *used_index = (guint)g_slist_nth_data(list, 0);
167         while (list) {
168                 if ((guint)list->data == req_index) {
169                         /* req_index is equal to one of used_index */
170                         *used_index = req_index;
171                         return;
172                 }
173                 list = g_slist_next(list);
174         }
175 }
176
177 static gint __imc_phonebook_compare_index(gconstpointer a, gconstpointer b)
178 {
179         guint index1 = (guint)a;
180         guint index2 = (guint)b;
181
182         return index1 - index2;
183 }
184
185 static void on_response_imc_phonebook_get_used_index(TcorePending *p,
186                 guint data_len, const void *data, void *user_data)
187 {
188         const TcoreAtResponse *at_resp = data;
189         ImcRespCbData *resp_cb_data = user_data;
190         CoreObject *co = tcore_pending_ref_core_object(p);
191         tcore_check_return_assert(at_resp != NULL);
192         tcore_check_return_assert(resp_cb_data != NULL);
193
194         dbg("Entry");
195
196         if (at_resp->success != TRUE) {
197                 err("Response NOK");
198                 return;
199         }
200
201         dbg("Response OK");
202
203         if (at_resp->lines == NULL) {
204                 err("at_resp->lines is NULL");
205         } else {
206                 GSList *lines = at_resp->lines;
207                 TelPbType *req_type;
208                 GSList **list = NULL;
209                 PrivateInfo *private_info = tcore_object_ref_user_data(co);
210                 tcore_check_return_assert(private_info != NULL);
211
212                 /* Select used_index_list by req_type */
213                 req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
214                 switch (*req_type) {
215                 case TEL_PB_FDN:
216                         list = &private_info->used_index_fdn;
217                         private_info->used_index_fdn_valid = TRUE;
218                         break;
219                 case TEL_PB_ADN:
220                         list = &private_info->used_index_adn;
221                         private_info->used_index_adn_valid = TRUE;
222                         break;
223                 case TEL_PB_SDN:
224                         list = &private_info->used_index_sdn;
225                         private_info->used_index_sdn_valid = TRUE;
226                         break;
227                 case TEL_PB_USIM:
228                         list = &private_info->used_index_usim;
229                         private_info->used_index_usim_valid = TRUE;
230                         break;
231                 }
232
233                 while (lines) {
234                         const gchar *line = lines->data;
235                         GSList *tokens = NULL;
236                         gchar *temp;
237
238                         dbg("Line: [%s]", line);
239
240                         tokens = tcore_at_tok_new(line);
241                         if (tokens == NULL) {
242                                 err("tokens is NULL");
243                                 return;
244                         }
245
246                         /* Get only used_index */
247                         temp = g_slist_nth_data(tokens, 0);
248                         if (temp) {
249                                 /* Insert used_index in PrivateInfo sorted in ascending */
250                                 *list = g_slist_insert_sorted(*list, (gpointer)atoi(temp),
251                                         __imc_phonebook_compare_index);
252                         }
253                         tcore_at_tok_free(tokens);
254
255                         /* Get next lines */
256                         lines = g_slist_next(lines);
257                 }
258                 dbg("pb_type: [%d], used_index Length: [%d]",
259                         *req_type, g_slist_length(*list));
260         }
261 }
262
263 static void __imc_phonebook_get_used_index(CoreObject *co, TelPbType pb_type, guint max_index)
264 {
265         gchar *at_cmd;
266         ImcRespCbData *resp_cb_data;
267         TelReturn ret = TEL_RETURN_FAILURE;
268
269         dbg("Entry");
270
271         /* AT-Command */
272         at_cmd = g_strdup_printf("AT+CPBR=1,%d", max_index);
273
274         /* Response callback data */
275         resp_cb_data = imc_create_resp_cb_data(NULL, NULL,
276                 (void *)&pb_type, sizeof(TelPbType));
277
278         /* Send Request to Modem */
279         ret = tcore_at_prepare_and_send_request(co,
280                 at_cmd, "+CPBR",
281                 TCORE_AT_COMMAND_TYPE_MULTILINE,
282                 TCORE_PENDING_PRIORITY_DEFAULT,
283                 NULL,
284                 on_response_imc_phonebook_get_used_index, resp_cb_data,
285                 on_send_imc_request, NULL,
286                 0, NULL, NULL);
287         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Used Index");
288
289         /* Free resources */
290         g_free(at_cmd);
291 }
292
293 static void on_response_imc_phonebook_get_support_list(TcorePending *p,
294                 guint data_len, const void *data, void *user_data)
295 {
296         const TcoreAtResponse *at_resp = data;
297         CoreObject *co = tcore_pending_ref_core_object(p);
298         TelPbInitInfo init_info = {0, };
299         tcore_check_return_assert(at_resp != NULL);
300
301         dbg("Entry");
302
303         if (at_resp->success != TRUE) {
304                 err("Response NOK");
305                 return;
306         }
307
308         dbg("Response OK");
309
310         if (at_resp->lines == NULL) {
311                 err("at_resp->lines is NULL");
312                 return;
313         } else {
314                 const gchar *line = (const gchar *)at_resp->lines->data;
315                 GSList *tokens = NULL;
316                 gchar *pb_type_list;
317                 gchar *pb_type;
318
319                 dbg("Line: [%s]", line);
320
321                 tokens = tcore_at_tok_new(line);
322                 if (tokens == NULL) {
323                         err("tokens is NULL");
324                         return;
325                 }
326
327                 pb_type_list = g_slist_nth_data(tokens, 0);
328                 pb_type = strtok(pb_type_list, "(,)");
329                 while (pb_type) {
330                         pb_type = tcore_at_tok_extract(pb_type);
331                         if (g_strcmp0(pb_type, "FD") == 0) {
332                                 init_info.pb_list.fdn = TRUE;
333                         } else if (g_strcmp0(pb_type, "SN") == 0) {
334                                 init_info.pb_list.sdn = TRUE;
335                         } else if (g_strcmp0(pb_type, "SM") == 0) {
336                                 TelSimCardType sim_type;
337                                 __imc_phonebook_get_sim_type(co, &sim_type);
338                                 if (sim_type == TEL_SIM_CARD_TYPE_USIM)
339                                         init_info.pb_list.usim = TRUE;
340                                 else
341                                         init_info.pb_list.adn = TRUE;
342                         }
343                         g_free(pb_type);
344                         /* Get Next pb_type */
345                         pb_type = strtok(NULL, "(,)");
346                 }
347                 tcore_at_tok_free(tokens);
348         }
349
350         dbg("FDN: [%s], ADN: [%s], SDN: [%s], USIM: [%s]",
351                 init_info.pb_list.fdn ? "TRUE" : "FALSE",
352                 init_info.pb_list.adn ? "TRUE" : "FALSE",
353                 init_info.pb_list.sdn ? "TRUE" : "FALSE",
354                 init_info.pb_list.usim ? "TRUE" : "FALSE");
355
356         init_info.init_status = TRUE;
357         tcore_phonebook_set_support_list(co, &init_info.pb_list);
358         tcore_phonebook_set_status(co, init_info.init_status);
359
360         /* Send Notification */
361         tcore_object_send_notification(co,
362                 TCORE_NOTIFICATION_PHONEBOOK_STATUS,
363                 sizeof(TelPbInitInfo), &init_info);
364 }
365
366 /*
367  * Operation - get_support_list
368  *
369  * Request -
370  * AT-Command: AT+CPBS=?
371  *
372  * Response -
373  * Success: (Single line)
374  *      (list of supported <storage>s)
375  *      OK
376  * Failure:
377  *      +CME ERROR: <error>
378  */
379 static void __imc_phonebook_get_support_list(CoreObject *co)
380 {
381         TelReturn ret;
382
383         dbg("Entry");
384
385         /* Send Request to Modem */
386         ret = tcore_at_prepare_and_send_request(co,
387                 "AT+CPBS=?", "+CPBS",
388                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
389                 TCORE_PENDING_PRIORITY_DEFAULT,
390                 NULL,
391                 on_response_imc_phonebook_get_support_list, NULL,
392                 on_send_imc_request, NULL,
393                 0, NULL, NULL);
394         IMC_CHECK_REQUEST_RET(ret, NULL, "Get Support List");
395 }
396
397 static gboolean on_notification_imc_phonebook_status(CoreObject *co,
398                 const void *event_info, void *user_data)
399 {
400         dbg("Phonebook Init Completed");
401
402         /* Get Supported list */
403         __imc_phonebook_get_support_list(co);
404
405         return TRUE;
406 }
407
408 static void on_response_imc_phonebook_get_info(TcorePending *p,
409                 guint data_len, const void *data, void *user_data)
410 {
411         const TcoreAtResponse *at_resp = data;
412         ImcRespCbData *resp_cb_data = user_data;
413         CoreObject *co = tcore_pending_ref_core_object(p);
414         TelPbResult result = TEL_PB_RESULT_FAILURE;
415         TelPbInfo pb_info = {0, };
416         tcore_check_return_assert(at_resp != NULL);
417         tcore_check_return_assert(resp_cb_data != NULL);
418
419         dbg("Entry");
420
421         if (at_resp->success != TRUE) {
422                 err("Response NOK");
423                 goto out;
424         }
425
426         dbg("Response OK");
427
428         if (at_resp->lines == NULL) {
429                 err("at_resp->lines is NULL");
430         } else {
431                 GSList *lines = at_resp->lines;
432                 const gchar *line;
433                 GSList *tokens = NULL;
434                 gchar *temp;
435                 gint used = 0, total = 0;
436                 gint nlen = 0, tlen = 0;
437                 TelPbType *req_type;
438                 PrivateInfo *private_info;
439
440                 /* +CPBS: <storage>[,<used>][,total] */
441                 line = g_slist_nth_data(lines, 0);
442                 dbg("First Line: [%s]", line);
443                 tokens = tcore_at_tok_new(line);
444                 if (tokens == NULL) {
445                         err("tokens is NULL");
446                         goto out;
447                 }
448
449                 /* Get used_count */
450                 temp = g_slist_nth_data(tokens, 1);
451                 if (temp)
452                         used = atoi(temp);
453                 /* Get total_count */
454                 temp = g_slist_nth_data(tokens, 2);
455                 if (temp)
456                         total = atoi(temp);
457
458                 tcore_at_tok_free(tokens);
459
460                 /* +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>] */
461                 line = g_slist_nth_data(lines, 1);
462                 dbg("Second Line: [%s]", line);
463                 tokens = tcore_at_tok_new(line);
464                 if (tokens == NULL) {
465                         err("tokens is NULL");
466                         goto out;
467                 }
468
469                 /* Get number Length */
470                 temp = g_slist_nth_data(tokens, 0);
471                 if (temp)
472                         nlen = atoi(temp);
473                 /* Get text Length */
474                 temp = g_slist_nth_data(tokens, 1);
475                 if (temp)
476                         tlen = atoi(temp);
477
478                 /* Set Response Data */
479                 req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
480                 pb_info.pb_type = *req_type;
481                 if (*req_type == TEL_PB_USIM) {
482                         pb_info.info_u.usim.max_count = total;
483                         pb_info.info_u.usim.used_count = used;
484                         pb_info.info_u.usim.max_num_len = nlen;
485                         pb_info.info_u.usim.max_text_len = tlen;
486                         /* Get group name Length */
487                         temp = g_slist_nth_data(tokens, 2);
488                         if (temp)
489                                 pb_info.info_u.usim.max_gas_len = atoi(temp);
490                         /* Get second name Length */
491                         temp = g_slist_nth_data(tokens, 3);
492                         if (temp)
493                                 pb_info.info_u.usim.max_sne_len = atoi(temp);
494                         /* Get email Length */
495                         temp = g_slist_nth_data(tokens, 4);
496                         if (temp)
497                                 pb_info.info_u.usim.max_email_len = atoi(temp);
498                 } else {
499                         pb_info.info_u.sim.max_count = total;
500                         pb_info.info_u.sim.used_count = used;
501                         pb_info.info_u.sim.max_num_len = nlen;
502                         pb_info.info_u.sim.max_text_len = tlen;
503                 }
504
505                 /* Set Request type in PrivateObject */
506                 tcore_phonebook_set_selected_type(co, *req_type);
507                 result = TEL_PB_RESULT_SUCCESS;
508                 tcore_at_tok_free(tokens);
509
510                 /* If don't have valid used_index, get used_index by req_type */
511                 private_info = tcore_object_ref_user_data(co);
512                 if ((*req_type == TEL_PB_FDN && private_info->used_index_fdn_valid == FALSE)
513                                 || (*req_type == TEL_PB_ADN && private_info->used_index_adn_valid == FALSE)
514                                 || (*req_type == TEL_PB_SDN && private_info->used_index_sdn_valid == FALSE)
515                                 || (*req_type == TEL_PB_USIM && private_info->used_index_usim_valid == FALSE))
516                         __imc_phonebook_get_used_index(co, *req_type, total);
517         }
518
519 out:
520         /* Invoke callback */
521         if (resp_cb_data->cb)
522                 resp_cb_data->cb(co, (gint)result, &pb_info, resp_cb_data->cb_data);
523
524         /* Free callback data */
525         imc_destroy_resp_cb_data(resp_cb_data);
526 }
527
528 static void on_response_imc_phonebook_read_record(TcorePending *p,
529                 guint data_len, const void *data, void *user_data)
530 {
531         const TcoreAtResponse *at_resp = data;
532         ImcRespCbData *resp_cb_data = user_data;
533         CoreObject *co = tcore_pending_ref_core_object(p);
534         TelPbResult result = TEL_PB_RESULT_FAILURE;
535         GSList *tokens = NULL;
536         gchar *index = NULL, *number = NULL, *name = NULL;
537         TelPbReadRecord read_record = {0, };
538         tcore_check_return_assert(at_resp != NULL);
539         tcore_check_return_assert(resp_cb_data != NULL);
540
541         dbg("Entry");
542
543         if (at_resp->success != TRUE) {
544                 err("Response NOK");
545                 goto out;
546         }
547
548         dbg("Response OK");
549
550         if (at_resp->lines == NULL) {
551                 err("at_resp->lines is NULL");
552         } else {
553                 const gchar *line = (const gchar *)at_resp->lines->data;
554                 TelPbType *req_type;
555                 GSList *list = NULL;
556
557                 dbg("Line: [%s]", line);
558
559                 tokens = tcore_at_tok_new(line);
560                 if (tokens == NULL) {
561                         err("tokens is NULL");
562                         goto out;
563                 }
564
565                 /* Get index */
566                 index = g_slist_nth_data(tokens, 0);
567                 if (index == NULL) {
568                         err("No index");
569                         goto out;
570                 }
571
572                 /* Get number */
573                 number = g_slist_nth_data(tokens, 1);
574                 if (number) {
575                         number = tcore_at_tok_extract(number);
576                 } else {
577                         err("No number");
578                         goto out;
579                 }
580
581                 /* Get name */
582                 name = g_slist_nth_data(tokens, 3);
583                 if (name) {
584                         name = tcore_at_tok_extract(name);
585                 } else {
586                         err("No name");
587                         goto out;
588                 }
589
590                 /* Set Request type in PrivateObject */
591                 req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
592                 tcore_phonebook_set_selected_type(co, *req_type);
593
594                 /* Set Response Data */
595                 read_record.index = atoi(index);
596                 read_record.pb_type = *req_type;
597
598                 /* Get used_index list by req_type */
599                 if (__imc_phonebook_get_index_list_by_type(co, *req_type, &list) == TRUE) {
600                         while (list) {
601                                 if ((guint)list->data == read_record.index) {
602                                         if ((list = g_slist_next(list)) != NULL) {
603                                                 /* If exist, set next_index */
604                                                 read_record.next_index = (guint)list->data;
605                                                 dbg("next_index is [%u]", read_record.next_index);
606                                         } else {
607                                                 /* read_record.index is the end of used_index */
608                                                 read_record.next_index = -1;
609                                                 dbg("End of used_index");
610                                         }
611                                         break;
612                                 }
613                                 list = g_slist_next(list);
614                         }
615                 } else {
616                         /* No PrivateInfo */
617                         read_record.next_index = 0;
618                 }
619
620                 if (*req_type == TEL_PB_USIM) {
621                         gchar *hidden, *group, *anr, *sne, *email;
622
623                         /* Get Name and Number */
624                         g_strlcpy(read_record.rec_u.usim.name, name, TEL_PB_TEXT_MAX_LEN + 1);
625                         g_strlcpy(read_record.rec_u.usim.number, number, TEL_PB_NUMBER_MAX_LEN + 1);
626
627                         /* Get Hidden */
628                         hidden = g_slist_nth_data(tokens, 4);
629                         if (hidden) {
630                                 read_record.rec_u.usim.hidden = atoi(hidden);
631                         }
632
633                         /* Get Group name */
634                         group = g_slist_nth_data(tokens, 5);
635                         if (group) {
636                                 group = tcore_at_tok_extract(group);
637                                 g_strlcpy(read_record.rec_u.usim.grp_name, group, TEL_PB_TEXT_MAX_LEN + 1);
638                                 g_free(group);
639                         }
640
641                         /* Get ANR */
642                         anr = g_slist_nth_data(tokens, 6);
643                         if (anr) {
644                                 anr = tcore_at_tok_extract(anr);
645                                 if (strlen(anr)) {
646                                         g_strlcpy(read_record.rec_u.usim.anr[0].number,
647                                                 anr, TEL_PB_NUMBER_MAX_LEN + 1);
648                                         read_record.rec_u.usim.anr_count = 1;
649                                 }
650                                 g_free(anr);
651                         }
652
653                         /* Get SNE */
654                         sne = g_slist_nth_data(tokens, 8);
655                         if (sne) {
656                                 sne = tcore_at_tok_extract(sne);
657                                 g_strlcpy(read_record.rec_u.usim.sne, sne, TEL_PB_TEXT_MAX_LEN + 1);
658                                 g_free(sne);
659                         }
660
661                         /* Get email */
662                         email = g_slist_nth_data(tokens, 9);
663                         if (email) {
664                                 email = tcore_at_tok_extract(email);
665                                 if (strlen(email)) {
666                                         g_strlcpy(read_record.rec_u.usim.email[0], email, TEL_PB_TEXT_MAX_LEN + 1);
667                                         read_record.rec_u.usim.email_count = 1;
668                                 }
669                                 g_free(email);
670                         }
671                 }
672                 else {
673                         /* Get Name and Number */
674                         g_strlcpy(read_record.rec_u.sim.name, name, TEL_PB_TEXT_MAX_LEN + 1);
675                         g_strlcpy(read_record.rec_u.sim.number, number, TEL_PB_NUMBER_MAX_LEN + 1);
676                 }
677
678                 result = TEL_PB_RESULT_SUCCESS;
679         }
680
681 out:
682         /* Invoke callback */
683         if (resp_cb_data->cb)
684                 resp_cb_data->cb(co, (gint)result, &read_record, resp_cb_data->cb_data);
685
686         /* Free callback data */
687         imc_destroy_resp_cb_data(resp_cb_data);
688
689         /* Free resources */
690         tcore_at_tok_free(tokens);
691         g_free(number);
692         g_free(name);
693 }
694
695 static void on_response_imc_phonebook_update_record(TcorePending *p,
696                 guint data_len, const void *data, void *user_data)
697 {
698         const TcoreAtResponse *at_resp = data;
699         ImcRespCbData *resp_cb_data = user_data;
700         CoreObject *co = tcore_pending_ref_core_object(p);
701         TelPbUpdateRecord *req_data;
702         TelPbResult result = TEL_PB_RESULT_FAILURE;
703         GSList *list = NULL;
704         tcore_check_return_assert(at_resp != NULL);
705         tcore_check_return_assert(resp_cb_data != NULL);
706
707         dbg("Entry");
708
709         if (at_resp->success != TRUE) {
710                 err("Response NOK");
711                 goto out;
712         }
713
714         dbg("Response OK");
715         result = TEL_PB_RESULT_SUCCESS;
716
717         /* Set Request type in PrivateObject */
718         req_data = (TelPbUpdateRecord *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
719         tcore_phonebook_set_selected_type(co, req_data->pb_type);
720
721         /* Get used_index list by req_type */
722         if (__imc_phonebook_get_index_list_by_type(co,
723                         req_data->pb_type, &list) != TRUE) {
724                 err("used_index list is NOT valid");
725         } else {
726                 list = g_slist_insert_sorted(list, (gpointer)req_data->index,
727                         __imc_phonebook_compare_index);
728         }
729
730 out:
731         /* Invoke callback */
732         if (resp_cb_data->cb)
733                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
734
735         /* Free callback data */
736         imc_destroy_resp_cb_data(resp_cb_data);
737 }
738
739 static void on_response_imc_phonebook_delete_record(TcorePending *p,
740                 guint data_len, const void *data, void *user_data)
741 {
742         const TcoreAtResponse *at_resp = data;
743         ImcRespCbData *resp_cb_data = user_data;
744         CoreObject *co = tcore_pending_ref_core_object(p);
745         TelPbRecordInfo *req_data;
746         GSList *list = NULL;
747         TelPbResult result = TEL_PB_RESULT_FAILURE;
748         tcore_check_return_assert(at_resp != NULL);
749         tcore_check_return_assert(resp_cb_data != NULL);
750
751         dbg("Entry");
752
753         if (at_resp->success != TRUE) {
754                 err("Response NOK");
755                 goto out;
756         }
757
758         dbg("Response OK");
759         result = TEL_PB_RESULT_SUCCESS;
760
761         /* Set Request type in PrivateObject */
762         req_data = (TelPbRecordInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
763         tcore_phonebook_set_selected_type(co, req_data->pb_type);
764
765         /* Get used_index list by req_type */
766         if (__imc_phonebook_get_index_list_by_type(co,
767                         req_data->pb_type, &list) != TRUE) {
768                 err("used_index list is NOT valid");
769         } else {
770                 list = g_slist_remove(list, (gconstpointer)req_data->index);
771                 dbg("Remove index: [%u]", req_data->index);
772         }
773
774 out:
775         /* Invoke callback */
776         if (resp_cb_data->cb)
777                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
778
779         /* Free callback data */
780         imc_destroy_resp_cb_data(resp_cb_data);
781 }
782
783 /*
784  * Operation - get_info
785  *
786  * Request -
787  * AT-Command: AT+CPBS?;+CPBF=?
788  *
789  * Response -
790  * Success: (Multi line)
791  *      +CPBS: <storage>[,<used>][,total]
792  *      +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>]
793  *      OK
794  * where,
795  * <nlength> Maximum length of field <number>
796  * <tlength> Maximum length of field <text>
797  * <glength> Maximum length of field <group>
798  * <slength> Maximum length of field <secondtext>
799  * <elength> Maximum length of field <email>
800  *
801  * Failure:
802  *      +CME ERROR: <error>
803  */
804 static TelReturn imc_phonebook_get_info(CoreObject *co,
805                 const TelPbType pb_type,
806                 TcoreObjectResponseCallback cb, void *cb_data)
807 {
808         gchar *at_cmd;
809         gchar *set_pb_cmd;
810         ImcRespCbData *resp_cb_data;
811         TelReturn ret = TEL_RETURN_FAILURE;
812
813         dbg("Entry");
814
815         /* Check whether pb_type is supported or not, and Select pb_type */
816         if (__imc_phonebook_check_and_select_type(co, pb_type, &set_pb_cmd) != TRUE) {
817                 return ret;
818         }
819
820         /* AT-Command */
821         at_cmd = g_strdup_printf("%s+CPBS?;+CPBF=?", set_pb_cmd);
822
823         /* Response callback data */
824         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
825                 (void *)&pb_type, sizeof(TelPbType));
826
827         /* Send Request to Modem */
828         ret = tcore_at_prepare_and_send_request(co,
829                 at_cmd, "+CPB",
830                 TCORE_AT_COMMAND_TYPE_MULTILINE,
831                 TCORE_PENDING_PRIORITY_DEFAULT,
832                 NULL,
833                 on_response_imc_phonebook_get_info, resp_cb_data,
834                 on_send_imc_request, NULL,
835                 0, NULL, NULL);
836         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Info");
837
838         /* Free resources */
839         g_free(at_cmd);
840         g_free(set_pb_cmd);
841
842         return ret;
843 }
844
845 /*
846  * Operation - read_record
847  *
848  * Request -
849  * AT-Command: AT+CPBR=<index>
850  * where,
851  * <index>
852  * 1    Integer type values in range of location numbers of phonebook memory
853  * ...
854  *
855  * Response -
856  * Success: (Single line);
857  *      +CPBR: <index>,<number>,<type>,<text>[,<hidden>][,<group>]
858  *      [,<adnumber>][,<adtype>][,<secondtext>][,<email>]]
859  *      OK
860  * where,
861  * <number> String type phone number of format <type>
862  * <type> Type of address octet in integer format
863  * <text> String type field of maximum length <tlength>
864  * <hidden> Indicates if the entry is hidden or not â€“ only available,
865  *              if a UICC with an active USIM application is present
866  * 0    Phonebook entry not hidden
867  * 1    Phonebook entry hidden
868  * <group> String type field of maximum length <glength>
869  * <adnumber> String type phone number of format <adtype>
870  * <adtype> Type of address octet in integer format
871  * <secondtext> String type field of maximum length <slength>
872  * <email> String type field of maximum length <elength>
873  *
874  * Failure:
875  *      +CME ERROR: <error>
876  */
877 static TelReturn imc_phonebook_read_record(CoreObject *co,
878                 const TelPbRecordInfo *record,
879                 TcoreObjectResponseCallback cb, void *cb_data)
880 {
881         gchar *at_cmd;
882         gchar *set_pb_cmd;
883         ImcRespCbData *resp_cb_data;
884         guint used_index = 0;
885         TelReturn ret = TEL_RETURN_FAILURE;
886
887         dbg("Entry");
888
889         /* Check whether pb_type is supported or not, and Select pb_type */
890         if (__imc_phonebook_check_and_select_type(co, record->pb_type, &set_pb_cmd) != TRUE) {
891                 return ret;
892         }
893
894         /* Check whether index is used or not */
895         __imc_phonebook_check_used_index(co, record->pb_type, record->index, &used_index);
896
897         /* AT-Command */
898         at_cmd = g_strdup_printf("%s+CPBR=%u", set_pb_cmd, used_index);
899
900         /* Response callback data */
901         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
902                 (void *)&(record->pb_type), sizeof(TelPbType));
903
904         /* Send Request to Modem */
905         ret = tcore_at_prepare_and_send_request(co,
906                 at_cmd, "+CPBR",
907                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
908                 TCORE_PENDING_PRIORITY_DEFAULT,
909                 NULL,
910                 on_response_imc_phonebook_read_record, resp_cb_data,
911                 on_send_imc_request, NULL,
912                 0, NULL, NULL);
913         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Read Record");
914
915         /* Free resources */
916         g_free(at_cmd);
917         g_free(set_pb_cmd);
918
919         return ret;
920 }
921
922 /*
923  * Operation - update_record
924  *
925  * Request -
926  * AT-Command: AT+CPBW=[<index>][,<number>[,<type>[,<text>[,<group>[,<adnumber>
927  *      [,<adtype>[,<secondtext>[,<email>[,<hidden>]]]]]]]]]
928  * where,
929  * ... same read_record Operation
930  *
931  * Response -
932  * Success: (No Result)
933  *      OK
934  * Failure:
935  *      +CME ERROR: <error>
936  */
937 static TelReturn imc_phonebook_update_record(CoreObject *co,
938                 const TelPbUpdateRecord *req_data,
939                 TcoreObjectResponseCallback cb, void *cb_data)
940 {
941         gchar *at_cmd;
942         gchar *set_pb_cmd;
943         ImcRespCbData *resp_cb_data;
944         TelReturn ret = TEL_RETURN_FAILURE;
945
946         dbg("Entry");
947
948         /* Check whether pb_type is supported or not, and Select pb_type */
949         if (__imc_phonebook_check_and_select_type(co, req_data->pb_type, &set_pb_cmd) != TRUE) {
950                 return ret;
951         }
952
953         /* Set AT-Command according pb_type */
954         if (req_data->pb_type == TEL_PB_USIM) {
955                 at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\",\"%s\",\"%s\",,\"%s\",\"%s\",%d",
956                         set_pb_cmd, req_data->index,
957                         req_data->rec_u.usim.number, req_data->rec_u.usim.name,
958                         req_data->rec_u.usim.grp_name, req_data->rec_u.usim.anr[0].number,
959                         req_data->rec_u.usim.sne, req_data->rec_u.usim.email[0],
960                         req_data->rec_u.usim.hidden);
961         } else {
962                 at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\"",
963                         set_pb_cmd, req_data->index,
964                         req_data->rec_u.sim.number,
965                         req_data->rec_u.sim.name);
966         }
967
968         /* Response callback data */
969         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
970                 (void *)req_data, sizeof(TelPbUpdateRecord));
971
972         /* Send Request to Modem */
973         ret = tcore_at_prepare_and_send_request(co,
974                 at_cmd, NULL,
975                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
976                 TCORE_PENDING_PRIORITY_DEFAULT,
977                 NULL,
978                 on_response_imc_phonebook_update_record, resp_cb_data,
979                 on_send_imc_request, NULL,
980                 0, NULL, NULL);
981         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Update Record");
982
983         /* Free resources */
984         g_free(at_cmd);
985         g_free(set_pb_cmd);
986
987         return ret;
988 }
989
990 /*
991  * Operation - delete_record
992  *
993  * Request -
994  * AT-Command: AT+CPBW=<index>
995  * where,
996  * <index>
997  * 1    Integer type values in range of location numbers of phonebook memory
998  * ...
999  *
1000  * Response -
1001  * Success: (No Result)
1002  *      OK
1003  * Failure:
1004  *      +CME ERROR: <error>
1005  */
1006 static TelReturn imc_phonebook_delete_record(CoreObject *co,
1007                 const TelPbRecordInfo *record,
1008                 TcoreObjectResponseCallback cb, void *cb_data)
1009 {
1010         gchar *at_cmd;
1011         gchar *set_pb_cmd;
1012         ImcRespCbData *resp_cb_data;
1013         TelReturn ret = TEL_RETURN_FAILURE;
1014
1015         dbg("Entry");
1016
1017         /* Check whether pb_type is supported or not, and Select pb_type */
1018         if (__imc_phonebook_check_and_select_type(co, record->pb_type, &set_pb_cmd) != TRUE) {
1019                 return ret;
1020         }
1021
1022         /* AT-Command */
1023         at_cmd = g_strdup_printf("%s+CPBW=%u", set_pb_cmd, record->index);
1024
1025         /* Response callback data */
1026         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
1027                 (void *)record, sizeof(TelPbRecordInfo));
1028
1029         /* Send Request to Modem */
1030         ret = tcore_at_prepare_and_send_request(co,
1031                 at_cmd, NULL,
1032                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1033                 TCORE_PENDING_PRIORITY_DEFAULT,
1034                 NULL,
1035                 on_response_imc_phonebook_delete_record, resp_cb_data,
1036                 on_send_imc_request, NULL,
1037                 0, NULL, NULL);
1038         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Delete Record");
1039
1040         /* Free resources */
1041         g_free(at_cmd);
1042         g_free(set_pb_cmd);
1043
1044         return ret;
1045 }
1046
1047 /* Phonebook Operations */
1048 static TcorePbOps imc_phonebook_ops = {
1049         .get_info = imc_phonebook_get_info,
1050         .read_record = imc_phonebook_read_record,
1051         .update_record = imc_phonebook_update_record,
1052         .delete_record = imc_phonebook_delete_record,
1053 };
1054
1055 gboolean imc_phonebook_init(TcorePlugin *p, CoreObject *co)
1056 {
1057         PrivateInfo *private_info;
1058
1059         dbg("Entry");
1060
1061         /* Set PrivateInfo */
1062         private_info = tcore_malloc0(sizeof(PrivateInfo));
1063         tcore_object_link_user_data(co, private_info);
1064
1065         /* Set operations */
1066         tcore_phonebook_set_ops(co, &imc_phonebook_ops);
1067
1068         /* Add Callbacks */
1069         tcore_object_add_callback(co, "+PBREADY", on_notification_imc_phonebook_status, NULL);
1070
1071         dbg("Exit");
1072         return TRUE;
1073 }
1074
1075 void imc_phonebook_exit(TcorePlugin *p, CoreObject *co)
1076 {
1077         PrivateInfo *private_info;
1078
1079         private_info = tcore_object_ref_user_data(co);
1080         tcore_check_return_assert(private_info != NULL);
1081
1082         /* Free PrivateInfo */
1083         g_slist_free_full(private_info->used_index_fdn, g_free);
1084         g_slist_free_full(private_info->used_index_adn, g_free);
1085         g_slist_free_full(private_info->used_index_sdn, g_free);
1086         g_slist_free_full(private_info->used_index_usim, g_free);
1087         tcore_free(private_info);
1088
1089         dbg("Exit");
1090 }