Enable TON/NPI with Get SCA
[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                 NULL,
283                 on_response_imc_phonebook_get_used_index, resp_cb_data,
284                 on_send_imc_request, NULL);
285         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Used Index");
286
287         /* Free resources */
288         g_free(at_cmd);
289 }
290
291 static void on_response_imc_phonebook_get_support_list(TcorePending *p,
292                 guint data_len, const void *data, void *user_data)
293 {
294         const TcoreAtResponse *at_resp = data;
295         CoreObject *co = tcore_pending_ref_core_object(p);
296         TelPbInitInfo init_info = {0, };
297         tcore_check_return_assert(at_resp != NULL);
298
299         dbg("Entry");
300
301         if (at_resp->success != TRUE) {
302                 err("Response NOK");
303                 return;
304         }
305
306         dbg("Response OK");
307
308         if (at_resp->lines == NULL) {
309                 err("at_resp->lines is NULL");
310                 return;
311         } else {
312                 const gchar *line = (const gchar *)at_resp->lines->data;
313                 GSList *tokens = NULL;
314                 gchar *pb_type_list;
315                 gchar *pb_type;
316
317                 dbg("Line: [%s]", line);
318
319                 tokens = tcore_at_tok_new(line);
320                 if (tokens == NULL) {
321                         err("tokens is NULL");
322                         return;
323                 }
324
325                 pb_type_list = g_slist_nth_data(tokens, 0);
326                 pb_type = strtok(pb_type_list, "(,)");
327                 while (pb_type) {
328                         pb_type = tcore_at_tok_extract(pb_type);
329                         if (g_strcmp0(pb_type, "FD") == 0) {
330                                 init_info.pb_list.fdn = TRUE;
331                         } else if (g_strcmp0(pb_type, "SN") == 0) {
332                                 init_info.pb_list.sdn = TRUE;
333                         } else if (g_strcmp0(pb_type, "SM") == 0) {
334                                 TelSimCardType sim_type;
335                                 __imc_phonebook_get_sim_type(co, &sim_type);
336                                 if (sim_type == TEL_SIM_CARD_TYPE_USIM)
337                                         init_info.pb_list.usim = TRUE;
338                                 else
339                                         init_info.pb_list.adn = TRUE;
340                         }
341                         g_free(pb_type);
342                         /* Get Next pb_type */
343                         pb_type = strtok(NULL, "(,)");
344                 }
345                 tcore_at_tok_free(tokens);
346         }
347
348         dbg("FDN: [%s], ADN: [%s], SDN: [%s], USIM: [%s]",
349                 init_info.pb_list.fdn ? "TRUE" : "FALSE",
350                 init_info.pb_list.adn ? "TRUE" : "FALSE",
351                 init_info.pb_list.sdn ? "TRUE" : "FALSE",
352                 init_info.pb_list.usim ? "TRUE" : "FALSE");
353
354         init_info.init_status = TRUE;
355         tcore_phonebook_set_support_list(co, &init_info.pb_list);
356         tcore_phonebook_set_status(co, init_info.init_status);
357
358         /* Send Notification */
359         tcore_object_send_notification(co,
360                 TCORE_NOTIFICATION_PHONEBOOK_STATUS,
361                 sizeof(TelPbInitInfo), &init_info);
362 }
363
364 /*
365  * Operation - get_support_list
366  *
367  * Request -
368  * AT-Command: AT+CPBS=?
369  *
370  * Response -
371  * Success: (Single line)
372  *      (list of supported <storage>s)
373  *      OK
374  * Failure:
375  *      +CME ERROR: <error>
376  */
377 static void __imc_phonebook_get_support_list(CoreObject *co)
378 {
379         TelReturn ret;
380
381         dbg("Entry");
382
383         /* Send Request to Modem */
384         ret = tcore_at_prepare_and_send_request(co,
385                 "AT+CPBS=?", "+CPBS",
386                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
387                 NULL,
388                 on_response_imc_phonebook_get_support_list, NULL,
389                 on_send_imc_request, NULL);
390         IMC_CHECK_REQUEST_RET(ret, NULL, "Get Support List");
391 }
392
393 static gboolean on_notification_imc_phonebook_status(CoreObject *co,
394                 const void *event_info, void *user_data)
395 {
396         dbg("Phonebook Init Completed");
397
398         /* Get Supported list */
399         __imc_phonebook_get_support_list(co);
400
401         return TRUE;
402 }
403
404 static void on_response_imc_phonebook_get_info(TcorePending *p,
405                 guint data_len, const void *data, void *user_data)
406 {
407         const TcoreAtResponse *at_resp = data;
408         ImcRespCbData *resp_cb_data = user_data;
409         CoreObject *co = tcore_pending_ref_core_object(p);
410         TelPbResult result = TEL_PB_RESULT_FAILURE;
411         TelPbInfo pb_info = {0, };
412         tcore_check_return_assert(at_resp != NULL);
413         tcore_check_return_assert(resp_cb_data != NULL);
414
415         dbg("Entry");
416
417         if (at_resp->success != TRUE) {
418                 err("Response NOK");
419                 goto out;
420         }
421
422         dbg("Response OK");
423
424         if (at_resp->lines == NULL) {
425                 err("at_resp->lines is NULL");
426         } else {
427                 GSList *lines = at_resp->lines;
428                 const gchar *line;
429                 GSList *tokens = NULL;
430                 gchar *temp;
431                 gint used = 0, total = 0;
432                 gint nlen = 0, tlen = 0;
433                 TelPbType *req_type;
434                 PrivateInfo *private_info;
435
436                 /* +CPBS: <storage>[,<used>][,total] */
437                 line = g_slist_nth_data(lines, 0);
438                 dbg("First Line: [%s]", line);
439                 tokens = tcore_at_tok_new(line);
440                 if (tokens == NULL) {
441                         err("tokens is NULL");
442                         goto out;
443                 }
444
445                 /* Get used_count */
446                 temp = g_slist_nth_data(tokens, 1);
447                 if (temp)
448                         used = atoi(temp);
449                 /* Get total_count */
450                 temp = g_slist_nth_data(tokens, 2);
451                 if (temp)
452                         total = atoi(temp);
453
454                 tcore_at_tok_free(tokens);
455
456                 /* +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>] */
457                 line = g_slist_nth_data(lines, 1);
458                 dbg("Second Line: [%s]", line);
459                 tokens = tcore_at_tok_new(line);
460                 if (tokens == NULL) {
461                         err("tokens is NULL");
462                         goto out;
463                 }
464
465                 /* Get number Length */
466                 temp = g_slist_nth_data(tokens, 0);
467                 if (temp)
468                         nlen = atoi(temp);
469                 /* Get text Length */
470                 temp = g_slist_nth_data(tokens, 1);
471                 if (temp)
472                         tlen = atoi(temp);
473
474                 /* Set Response Data */
475                 req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
476                 pb_info.pb_type = *req_type;
477                 if (*req_type == TEL_PB_USIM) {
478                         pb_info.info_u.usim.max_count = total;
479                         pb_info.info_u.usim.used_count = used;
480                         pb_info.info_u.usim.max_num_len = nlen;
481                         pb_info.info_u.usim.max_text_len = tlen;
482                         /* Get group name Length */
483                         temp = g_slist_nth_data(tokens, 2);
484                         if (temp)
485                                 pb_info.info_u.usim.max_gas_len = atoi(temp);
486                         /* Get second name Length */
487                         temp = g_slist_nth_data(tokens, 3);
488                         if (temp)
489                                 pb_info.info_u.usim.max_sne_len = atoi(temp);
490                         /* Get email Length */
491                         temp = g_slist_nth_data(tokens, 4);
492                         if (temp)
493                                 pb_info.info_u.usim.max_email_len = atoi(temp);
494                 } else {
495                         pb_info.info_u.sim.max_count = total;
496                         pb_info.info_u.sim.used_count = used;
497                         pb_info.info_u.sim.max_num_len = nlen;
498                         pb_info.info_u.sim.max_text_len = tlen;
499                 }
500
501                 /* Set Request type in PrivateObject */
502                 tcore_phonebook_set_selected_type(co, *req_type);
503                 result = TEL_PB_RESULT_SUCCESS;
504                 tcore_at_tok_free(tokens);
505
506                 /* If don't have valid used_index, get used_index by req_type */
507                 private_info = tcore_object_ref_user_data(co);
508                 if ((*req_type == TEL_PB_FDN && private_info->used_index_fdn_valid == FALSE)
509                                 || (*req_type == TEL_PB_ADN && private_info->used_index_adn_valid == FALSE)
510                                 || (*req_type == TEL_PB_SDN && private_info->used_index_sdn_valid == FALSE)
511                                 || (*req_type == TEL_PB_USIM && private_info->used_index_usim_valid == FALSE))
512                         __imc_phonebook_get_used_index(co, *req_type, total);
513         }
514
515 out:
516         /* Invoke callback */
517         if (resp_cb_data->cb)
518                 resp_cb_data->cb(co, (gint)result, &pb_info, resp_cb_data->cb_data);
519
520         /* Free callback data */
521         imc_destroy_resp_cb_data(resp_cb_data);
522 }
523
524 static void on_response_imc_phonebook_read_record(TcorePending *p,
525                 guint data_len, const void *data, void *user_data)
526 {
527         const TcoreAtResponse *at_resp = data;
528         ImcRespCbData *resp_cb_data = user_data;
529         CoreObject *co = tcore_pending_ref_core_object(p);
530         TelPbResult result = TEL_PB_RESULT_FAILURE;
531         GSList *tokens = NULL;
532         gchar *index = NULL, *number = NULL, *name = NULL;
533         TelPbReadRecord read_record = {0, };
534         tcore_check_return_assert(at_resp != NULL);
535         tcore_check_return_assert(resp_cb_data != NULL);
536
537         dbg("Entry");
538
539         if (at_resp->success != TRUE) {
540                 err("Response NOK");
541                 goto out;
542         }
543
544         dbg("Response OK");
545
546         if (at_resp->lines == NULL) {
547                 err("at_resp->lines is NULL");
548         } else {
549                 const gchar *line = (const gchar *)at_resp->lines->data;
550                 TelPbType *req_type;
551                 GSList *list = NULL;
552
553                 dbg("Line: [%s]", line);
554
555                 tokens = tcore_at_tok_new(line);
556                 if (tokens == NULL) {
557                         err("tokens is NULL");
558                         goto out;
559                 }
560
561                 /* Get index */
562                 index = g_slist_nth_data(tokens, 0);
563                 if (index == NULL) {
564                         err("No index");
565                         goto out;
566                 }
567
568                 /* Get number */
569                 number = g_slist_nth_data(tokens, 1);
570                 if (number) {
571                         number = tcore_at_tok_extract(number);
572                 } else {
573                         err("No number");
574                         goto out;
575                 }
576
577                 /* Get name */
578                 name = g_slist_nth_data(tokens, 3);
579                 if (name) {
580                         name = tcore_at_tok_extract(name);
581                 } else {
582                         err("No name");
583                         goto out;
584                 }
585
586                 /* Set Request type in PrivateObject */
587                 req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
588                 tcore_phonebook_set_selected_type(co, *req_type);
589
590                 /* Set Response Data */
591                 read_record.index = atoi(index);
592                 read_record.pb_type = *req_type;
593
594                 /* Get used_index list by req_type */
595                 if (__imc_phonebook_get_index_list_by_type(co, *req_type, &list) == TRUE) {
596                         while (list) {
597                                 if ((guint)list->data == read_record.index) {
598                                         if ((list = g_slist_next(list)) != NULL) {
599                                                 /* If exist, set next_index */
600                                                 read_record.next_index = (guint)list->data;
601                                                 dbg("next_index is [%u]", read_record.next_index);
602                                         } else {
603                                                 /* read_record.index is the end of used_index */
604                                                 read_record.next_index = -1;
605                                                 dbg("End of used_index");
606                                         }
607                                         break;
608                                 }
609                                 list = g_slist_next(list);
610                         }
611                 } else {
612                         /* No PrivateInfo */
613                         read_record.next_index = 0;
614                 }
615
616                 if (*req_type == TEL_PB_USIM) {
617                         gchar *hidden, *group, *anr, *sne, *email;
618
619                         /* Get Name and Number */
620                         g_strlcpy(read_record.rec_u.usim.name, name, TEL_PB_TEXT_MAX_LEN + 1);
621                         g_strlcpy(read_record.rec_u.usim.number, number, TEL_PB_NUMBER_MAX_LEN + 1);
622
623                         /* Get Hidden */
624                         hidden = g_slist_nth_data(tokens, 4);
625                         if (hidden) {
626                                 read_record.rec_u.usim.hidden = atoi(hidden);
627                         }
628
629                         /* Get Group name */
630                         group = g_slist_nth_data(tokens, 5);
631                         if (group) {
632                                 group = tcore_at_tok_extract(group);
633                                 g_strlcpy(read_record.rec_u.usim.grp_name, group, TEL_PB_TEXT_MAX_LEN + 1);
634                                 g_free(group);
635                         }
636
637                         /* Get ANR */
638                         anr = g_slist_nth_data(tokens, 6);
639                         if (anr) {
640                                 anr = tcore_at_tok_extract(anr);
641                                 if (strlen(anr)) {
642                                         g_strlcpy(read_record.rec_u.usim.anr[0].number,
643                                                 anr, TEL_PB_NUMBER_MAX_LEN + 1);
644                                         read_record.rec_u.usim.anr_count = 1;
645                                 }
646                                 g_free(anr);
647                         }
648
649                         /* Get SNE */
650                         sne = g_slist_nth_data(tokens, 8);
651                         if (sne) {
652                                 sne = tcore_at_tok_extract(sne);
653                                 g_strlcpy(read_record.rec_u.usim.sne, sne, TEL_PB_TEXT_MAX_LEN + 1);
654                                 g_free(sne);
655                         }
656
657                         /* Get email */
658                         email = g_slist_nth_data(tokens, 9);
659                         if (email) {
660                                 email = tcore_at_tok_extract(email);
661                                 if (strlen(email)) {
662                                         g_strlcpy(read_record.rec_u.usim.email[0], email, TEL_PB_TEXT_MAX_LEN + 1);
663                                         read_record.rec_u.usim.email_count = 1;
664                                 }
665                                 g_free(email);
666                         }
667                 }
668                 else {
669                         /* Get Name and Number */
670                         g_strlcpy(read_record.rec_u.sim.name, name, TEL_PB_TEXT_MAX_LEN + 1);
671                         g_strlcpy(read_record.rec_u.sim.number, number, TEL_PB_NUMBER_MAX_LEN + 1);
672                 }
673
674                 result = TEL_PB_RESULT_SUCCESS;
675         }
676
677 out:
678         /* Invoke callback */
679         if (resp_cb_data->cb)
680                 resp_cb_data->cb(co, (gint)result, &read_record, resp_cb_data->cb_data);
681
682         /* Free callback data */
683         imc_destroy_resp_cb_data(resp_cb_data);
684
685         /* Free resources */
686         tcore_at_tok_free(tokens);
687         g_free(number);
688         g_free(name);
689 }
690
691 static void on_response_imc_phonebook_update_record(TcorePending *p,
692                 guint data_len, const void *data, void *user_data)
693 {
694         const TcoreAtResponse *at_resp = data;
695         ImcRespCbData *resp_cb_data = user_data;
696         CoreObject *co = tcore_pending_ref_core_object(p);
697         TelPbUpdateRecord *req_data;
698         TelPbResult result = TEL_PB_RESULT_FAILURE;
699         GSList *list = NULL;
700         tcore_check_return_assert(at_resp != NULL);
701         tcore_check_return_assert(resp_cb_data != NULL);
702
703         dbg("Entry");
704
705         if (at_resp->success != TRUE) {
706                 err("Response NOK");
707                 goto out;
708         }
709
710         dbg("Response OK");
711         result = TEL_PB_RESULT_SUCCESS;
712
713         /* Set Request type in PrivateObject */
714         req_data = (TelPbUpdateRecord *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
715         tcore_phonebook_set_selected_type(co, req_data->pb_type);
716
717         /* Get used_index list by req_type */
718         if (__imc_phonebook_get_index_list_by_type(co,
719                         req_data->pb_type, &list) != TRUE) {
720                 err("used_index list is NOT valid");
721         } else {
722                 list = g_slist_insert_sorted(list, (gpointer)req_data->index,
723                         __imc_phonebook_compare_index);
724         }
725
726 out:
727         /* Invoke callback */
728         if (resp_cb_data->cb)
729                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
730
731         /* Free callback data */
732         imc_destroy_resp_cb_data(resp_cb_data);
733 }
734
735 static void on_response_imc_phonebook_delete_record(TcorePending *p,
736                 guint data_len, const void *data, void *user_data)
737 {
738         const TcoreAtResponse *at_resp = data;
739         ImcRespCbData *resp_cb_data = user_data;
740         CoreObject *co = tcore_pending_ref_core_object(p);
741         TelPbRecordInfo *req_data;
742         GSList *list = NULL;
743         TelPbResult result = TEL_PB_RESULT_FAILURE;
744         tcore_check_return_assert(at_resp != NULL);
745         tcore_check_return_assert(resp_cb_data != NULL);
746
747         dbg("Entry");
748
749         if (at_resp->success != TRUE) {
750                 err("Response NOK");
751                 goto out;
752         }
753
754         dbg("Response OK");
755         result = TEL_PB_RESULT_SUCCESS;
756
757         /* Set Request type in PrivateObject */
758         req_data = (TelPbRecordInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
759         tcore_phonebook_set_selected_type(co, req_data->pb_type);
760
761         /* Get used_index list by req_type */
762         if (__imc_phonebook_get_index_list_by_type(co,
763                         req_data->pb_type, &list) != TRUE) {
764                 err("used_index list is NOT valid");
765         } else {
766                 list = g_slist_remove(list, (gconstpointer)req_data->index);
767                 dbg("Remove index: [%u]", req_data->index);
768         }
769
770 out:
771         /* Invoke callback */
772         if (resp_cb_data->cb)
773                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
774
775         /* Free callback data */
776         imc_destroy_resp_cb_data(resp_cb_data);
777 }
778
779 /*
780  * Operation - get_info
781  *
782  * Request -
783  * AT-Command: AT+CPBS?;+CPBF=?
784  *
785  * Response -
786  * Success: (Multi line)
787  *      +CPBS: <storage>[,<used>][,total]
788  *      +CPBF: [<nlength>],[<tlength>],[<glength>],[<slength>],[<elength>]
789  *      OK
790  * where,
791  * <nlength> Maximum length of field <number>
792  * <tlength> Maximum length of field <text>
793  * <glength> Maximum length of field <group>
794  * <slength> Maximum length of field <secondtext>
795  * <elength> Maximum length of field <email>
796  *
797  * Failure:
798  *      +CME ERROR: <error>
799  */
800 static TelReturn imc_phonebook_get_info(CoreObject *co,
801                 const TelPbType pb_type,
802                 TcoreObjectResponseCallback cb, void *cb_data)
803 {
804         gchar *at_cmd;
805         gchar *set_pb_cmd;
806         ImcRespCbData *resp_cb_data;
807         TelReturn ret = TEL_RETURN_FAILURE;
808
809         dbg("Entry");
810
811         /* Check whether pb_type is supported or not, and Select pb_type */
812         if (__imc_phonebook_check_and_select_type(co, pb_type, &set_pb_cmd) != TRUE) {
813                 return ret;
814         }
815
816         /* AT-Command */
817         at_cmd = g_strdup_printf("%s+CPBS?;+CPBF=?", set_pb_cmd);
818
819         /* Response callback data */
820         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
821                 (void *)&pb_type, sizeof(TelPbType));
822
823         /* Send Request to Modem */
824         ret = tcore_at_prepare_and_send_request(co,
825                 at_cmd, "+CPB",
826                 TCORE_AT_COMMAND_TYPE_MULTILINE,
827                 NULL,
828                 on_response_imc_phonebook_get_info, resp_cb_data,
829                 on_send_imc_request, NULL);
830         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Info");
831
832         /* Free resources */
833         g_free(at_cmd);
834         g_free(set_pb_cmd);
835
836         return ret;
837 }
838
839 /*
840  * Operation - read_record
841  *
842  * Request -
843  * AT-Command: AT+CPBR=<index>
844  * where,
845  * <index>
846  * 1    Integer type values in range of location numbers of phonebook memory
847  * ...
848  *
849  * Response -
850  * Success: (Single line);
851  *      +CPBR: <index>,<number>,<type>,<text>[,<hidden>][,<group>]
852  *      [,<adnumber>][,<adtype>][,<secondtext>][,<email>]]
853  *      OK
854  * where,
855  * <number> String type phone number of format <type>
856  * <type> Type of address octet in integer format
857  * <text> String type field of maximum length <tlength>
858  * <hidden> Indicates if the entry is hidden or not â€“ only available,
859  *              if a UICC with an active USIM application is present
860  * 0    Phonebook entry not hidden
861  * 1    Phonebook entry hidden
862  * <group> String type field of maximum length <glength>
863  * <adnumber> String type phone number of format <adtype>
864  * <adtype> Type of address octet in integer format
865  * <secondtext> String type field of maximum length <slength>
866  * <email> String type field of maximum length <elength>
867  *
868  * Failure:
869  *      +CME ERROR: <error>
870  */
871 static TelReturn imc_phonebook_read_record(CoreObject *co,
872                 const TelPbRecordInfo *record,
873                 TcoreObjectResponseCallback cb, void *cb_data)
874 {
875         gchar *at_cmd;
876         gchar *set_pb_cmd;
877         ImcRespCbData *resp_cb_data;
878         guint used_index = 0;
879         TelReturn ret = TEL_RETURN_FAILURE;
880
881         dbg("Entry");
882
883         /* Check whether pb_type is supported or not, and Select pb_type */
884         if (__imc_phonebook_check_and_select_type(co, record->pb_type, &set_pb_cmd) != TRUE) {
885                 return ret;
886         }
887
888         /* Check whether index is used or not */
889         __imc_phonebook_check_used_index(co, record->pb_type, record->index, &used_index);
890
891         /* AT-Command */
892         at_cmd = g_strdup_printf("%s+CPBR=%u", set_pb_cmd, used_index);
893
894         /* Response callback data */
895         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
896                 (void *)&(record->pb_type), sizeof(TelPbType));
897
898         /* Send Request to Modem */
899         ret = tcore_at_prepare_and_send_request(co,
900                 at_cmd, "+CPBR",
901                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
902                 NULL,
903                 on_response_imc_phonebook_read_record, resp_cb_data,
904                 on_send_imc_request, NULL);
905         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Read Record");
906
907         /* Free resources */
908         g_free(at_cmd);
909         g_free(set_pb_cmd);
910
911         return ret;
912 }
913
914 /*
915  * Operation - update_record
916  *
917  * Request -
918  * AT-Command: AT+CPBW=[<index>][,<number>[,<type>[,<text>[,<group>[,<adnumber>
919  *      [,<adtype>[,<secondtext>[,<email>[,<hidden>]]]]]]]]]
920  * where,
921  * ... same read_record Operation
922  *
923  * Response -
924  * Success: (No Result)
925  *      OK
926  * Failure:
927  *      +CME ERROR: <error>
928  */
929 static TelReturn imc_phonebook_update_record(CoreObject *co,
930                 const TelPbUpdateRecord *req_data,
931                 TcoreObjectResponseCallback cb, void *cb_data)
932 {
933         gchar *at_cmd;
934         gchar *set_pb_cmd;
935         ImcRespCbData *resp_cb_data;
936         TelReturn ret = TEL_RETURN_FAILURE;
937
938         dbg("Entry");
939
940         /* Check whether pb_type is supported or not, and Select pb_type */
941         if (__imc_phonebook_check_and_select_type(co, req_data->pb_type, &set_pb_cmd) != TRUE) {
942                 return ret;
943         }
944
945         /* Set AT-Command according pb_type */
946         if (req_data->pb_type == TEL_PB_USIM) {
947                 at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\",\"%s\",\"%s\",,\"%s\",\"%s\",%d",
948                         set_pb_cmd, req_data->index,
949                         req_data->rec_u.usim.number, req_data->rec_u.usim.name,
950                         req_data->rec_u.usim.grp_name, req_data->rec_u.usim.anr[0].number,
951                         req_data->rec_u.usim.sne, req_data->rec_u.usim.email[0],
952                         req_data->rec_u.usim.hidden);
953         } else {
954                 at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\"",
955                         set_pb_cmd, req_data->index,
956                         req_data->rec_u.sim.number,
957                         req_data->rec_u.sim.name);
958         }
959
960         /* Response callback data */
961         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
962                 (void *)req_data, sizeof(TelPbUpdateRecord));
963
964         /* Send Request to Modem */
965         ret = tcore_at_prepare_and_send_request(co,
966                 at_cmd, NULL,
967                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
968                 NULL,
969                 on_response_imc_phonebook_update_record, resp_cb_data,
970                 on_send_imc_request, NULL);
971         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Update Record");
972
973         /* Free resources */
974         g_free(at_cmd);
975         g_free(set_pb_cmd);
976
977         return ret;
978 }
979
980 /*
981  * Operation - delete_record
982  *
983  * Request -
984  * AT-Command: AT+CPBW=<index>
985  * where,
986  * <index>
987  * 1    Integer type values in range of location numbers of phonebook memory
988  * ...
989  *
990  * Response -
991  * Success: (No Result)
992  *      OK
993  * Failure:
994  *      +CME ERROR: <error>
995  */
996 static TelReturn imc_phonebook_delete_record(CoreObject *co,
997                 const TelPbRecordInfo *record,
998                 TcoreObjectResponseCallback cb, void *cb_data)
999 {
1000         gchar *at_cmd;
1001         gchar *set_pb_cmd;
1002         ImcRespCbData *resp_cb_data;
1003         TelReturn ret = TEL_RETURN_FAILURE;
1004
1005         dbg("Entry");
1006
1007         /* Check whether pb_type is supported or not, and Select pb_type */
1008         if (__imc_phonebook_check_and_select_type(co, record->pb_type, &set_pb_cmd) != TRUE) {
1009                 return ret;
1010         }
1011
1012         /* AT-Command */
1013         at_cmd = g_strdup_printf("%s+CPBW=%u", set_pb_cmd, record->index);
1014
1015         /* Response callback data */
1016         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
1017                 (void *)record, sizeof(TelPbRecordInfo));
1018
1019         /* Send Request to Modem */
1020         ret = tcore_at_prepare_and_send_request(co,
1021                 at_cmd, NULL,
1022                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1023                 NULL,
1024                 on_response_imc_phonebook_delete_record, resp_cb_data,
1025                 on_send_imc_request, NULL);
1026         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Delete Record");
1027
1028         /* Free resources */
1029         g_free(at_cmd);
1030         g_free(set_pb_cmd);
1031
1032         return ret;
1033 }
1034
1035 /* Phonebook Operations */
1036 static TcorePbOps imc_phonebook_ops = {
1037         .get_info = imc_phonebook_get_info,
1038         .read_record = imc_phonebook_read_record,
1039         .update_record = imc_phonebook_update_record,
1040         .delete_record = imc_phonebook_delete_record,
1041 };
1042
1043 gboolean imc_phonebook_init(TcorePlugin *p, CoreObject *co)
1044 {
1045         PrivateInfo *private_info;
1046
1047         dbg("Entry");
1048
1049         /* Set PrivateInfo */
1050         private_info = tcore_malloc0(sizeof(PrivateInfo));
1051         tcore_object_link_user_data(co, private_info);
1052
1053         /* Set operations */
1054         tcore_phonebook_set_ops(co, &imc_phonebook_ops);
1055
1056         /* Add Callbacks */
1057         tcore_object_add_callback(co, "+PBREADY", on_notification_imc_phonebook_status, NULL);
1058
1059         dbg("Exit");
1060         return TRUE;
1061 }
1062
1063 void imc_phonebook_exit(TcorePlugin *p, CoreObject *co)
1064 {
1065         PrivateInfo *private_info;
1066
1067         private_info = tcore_object_ref_user_data(co);
1068         tcore_check_return_assert(private_info != NULL);
1069
1070         /* Free PrivateInfo */
1071         g_slist_free_full(private_info->used_index_fdn, g_free);
1072         g_slist_free_full(private_info->used_index_adn, g_free);
1073         g_slist_free_full(private_info->used_index_sdn, g_free);
1074         g_slist_free_full(private_info->used_index_usim, g_free);
1075         tcore_free(private_info);
1076
1077         dbg("Exit");
1078 }