Get sim mail box info
[platform/core/telephony/tel-plugin-imc.git] / src / imc_network.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 #include <tzplatform_config.h>
34
35 #include <co_network.h>
36
37 #include "imc_network.h"
38 #include "imc_common.h"
39
40 #define IMC_NETWORK_BASE_16     16
41
42 typedef enum {
43         IMC_NETWORK_SEARCH_STATE_NO_SEARCH,
44         IMC_NETWORK_SEARCH_STATE_IN_PROGRESS,
45         IMC_NETWORK_SEARCH_STATE_CANCELLED
46 } ImcNetworkSearchState;
47
48 typedef struct {
49         ImcNetworkSearchState search_state;
50 } CustomData;
51
52 typedef struct {
53         CoreObject *co;
54         TelNetworkResult result;
55 } ImcNetworkCancelSearch;
56
57 static TelNetworkAct __imc_network_map_act(guint act)
58 {
59         /*
60          * <ACT>
61          * 0    GSM
62          * 2    UTRAN
63          * 3    GSM w/EGPRS
64          * 4    UTRAN w/HSDPA
65          * 5    UTRAN w/HSUPA
66          * 6    UTRAN w/HSDPA and HSUPA
67          */
68         switch (act) {
69         case 0:
70                 return TEL_NETWORK_ACT_GSM;
71         case 2:
72                 return TEL_NETWORK_ACT_UMTS;
73         case 3:
74                 return TEL_NETWORK_ACT_EGPRS;
75         case 4:
76                 return TEL_NETWORK_ACT_HSDPA;
77         case 5:
78                 return TEL_NETWORK_ACT_HSUPA;
79         case 6:
80                 return TEL_NETWORK_ACT_HSPA;
81         default:
82                 return TEL_NETWORK_ACT_UNKNOWN;
83         }
84 }
85
86 static TelNetworkRegStatus __imc_network_map_stat(guint stat)
87 {
88         /*
89          * <stat>
90          * 0    Not registered, ME is not currently searching a
91          *      new operator to register to
92          * 1    Registered, home network
93          * 2    Not registered, but ME is currently searching a
94          *      new operator to register
95          * 3    Registration denied
96          * 4    Unknown
97          * 5    Registered, in roaming
98          */
99         switch (stat) {
100         case 0:
101                 return TEL_NETWORK_REG_STATUS_UNREGISTERED;
102         case 1:
103                 return TEL_NETWORK_REG_STATUS_REGISTERED;
104         case 2:
105                 return TEL_NETWORK_REG_STATUS_SEARCHING;
106         case 3:
107                 return TEL_NETWORK_REG_STATUS_DENIED;
108         case 4:
109                 return TEL_NETWORK_REG_STATUS_UNKNOWN;
110         case 5:
111                 return TEL_NETWORK_REG_STATUS_ROAMING;
112         default:
113                 return TEL_NETWORK_REG_STATUS_UNKNOWN;
114         }
115 }
116
117 static void __on_response_imc_network_registration(TcorePending *p,
118         guint data_len, const void *data, void *user_data)
119 {
120         const TcoreAtResponse *at_resp = data;
121         dbg("Entry");
122
123         if (at_resp && at_resp->success) {
124                 dbg("Network Registration - [OK]");
125         } else {
126                 err("Network Registration - [NOK]");
127         }
128 }
129
130 static void __imc_network_register_to_network(CoreObject *co)
131 {
132         TelReturn ret;
133
134         /* Send Request to modem */
135         ret = tcore_at_prepare_and_send_request(co,
136                 "AT+COPS=0", NULL,
137                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
138                 NULL,
139                 __on_response_imc_network_registration, NULL,
140                 on_send_imc_request, NULL);
141         dbg("Sending Network Registration request: [%s]",
142                 (ret == TEL_RETURN_SUCCESS ? "SUCCESS" : "FAIL"));
143 }
144
145 static void __on_response_imc_network_fetch_nw_name_internal(CoreObject *co,
146         gint result, const void *response, void *user_data)
147 {
148         TelNetworkIdentityInfo *identity = (TelNetworkIdentityInfo *)response;
149
150         /* Send notification if result is SUCCESS */
151         if (result == TEL_NETWORK_RESULT_SUCCESS)
152                 tcore_object_send_notification(co,
153                         TCORE_NOTIFICATION_NETWORK_IDENTITY,
154                         sizeof(TelNetworkIdentityInfo), identity);
155 }
156
157 static TcoreHookReturn __on_response_imc_hook_set_flight_mode(CoreObject *co,
158         gint result, TcoreCommand command, const void *response, const void *user_data)
159 {
160
161         tcore_check_return_value(result == TEL_MODEM_RESULT_SUCCESS,
162                 TCORE_HOOK_RETURN_CONTINUE);
163
164         dbg("Flight mode 'disabled', register to Network");
165
166         /*
167          * TODO - Check for selection_mode
168          *      Need to check if it is Manual or Automatic and based on
169          *      that need to initiate Network Registratin accordingly.
170          */
171         __imc_network_register_to_network(co);
172
173         return TCORE_HOOK_RETURN_CONTINUE;
174 }
175
176 static void __on_response_imc_network_fetch_nw_name(TcorePending *p,
177         guint data_len, const void *data, void *user_data)
178 {
179         const TcoreAtResponse *at_resp = data;
180         CoreObject *co = tcore_pending_ref_core_object(p);
181         ImcRespCbData *resp_cb_data = user_data;
182         TelNetworkIdentityInfo identity = {0, };
183
184         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE;
185
186         dbg("Enter");
187
188         tcore_check_return_assert(co != NULL);
189         tcore_check_return_assert(resp_cb_data != NULL);
190
191         if (at_resp && at_resp->success) {
192                 if (at_resp->lines) {
193                         const gchar *line;
194                         GSList *tokens = NULL;
195                         gchar *token_str;
196                         guint i, nol;
197
198                         /* Validate that only 3 lines of response is received */
199                         nol = g_slist_length(at_resp->lines);
200                         if (nol > 3) {
201                                 err("Invalid response message");
202                                 return;
203                         }
204
205                         /* Process the Multi-line response */
206                         for (i = 0; i < nol; i++) {
207                                 line = g_slist_nth_data(at_resp->lines, i);
208
209                                 /*
210                                  * Tokenize
211                                  *
212                                  * +XCOPS: <type>[,<name>[,<display_condition>]]
213                                  */
214                                 dbg("<line> : [%s]", line);
215                                 tokens = tcore_at_tok_new(line);
216
217                                 if ((token_str = tcore_at_tok_nth(tokens, 0))) {
218                                         guint type = atoi(token_str);
219                                         dbg("<type> : [%d]", type);
220
221                                         switch (type) {
222                                         case 0: /* PLMN (mcc, mnc) */
223                                                 if ((token_str = tcore_at_tok_nth(tokens, 1))) {
224                                                         if (strlen(token_str) > 0) {
225                                                                 identity.plmn = tcore_at_tok_extract((const char *)token_str);
226
227                                                                 /* Update PLMN */
228                                                                 tcore_network_set_plmn( co, identity.plmn);
229                                                         }
230                                                 }
231                                         break;
232
233                                         case 1: /* Short Name in ROM (NV-RAM) */
234                                         case 3: /* Short Network Operator Name (CPHS) */
235                                         case 5: /* Short NITZ Name */
236                                                 if ((token_str = tcore_at_tok_nth(tokens, 1))) {
237                                                         if (strlen(token_str) > 0) {
238                                                                 identity.short_name = tcore_at_tok_extract((const char *)token_str);
239
240
241                                                                 /* Update Short name */
242                                                                 tcore_network_set_short_name(co, identity.short_name);
243                                                         }
244                                                 }
245                                         break;
246
247                                         case 2: /* Long Name in ROM (NV-RAM) */
248                                         case 4: /* Long Network Operator Name (CPHS) */
249                                         case 6: /* Full NITZ Name */
250                                                 if ((token_str = tcore_at_tok_nth(tokens, 1))) {
251                                                         if (strlen(token_str) > 0) {
252                                                                 identity.long_name = tcore_at_tok_extract((const char *)token_str);
253
254                                                                 /* Update Long name */
255                                                                 tcore_network_set_long_name(co, identity.long_name);
256                                                         }
257                                                 }
258                                         break;
259
260                                         default:
261                                         break;
262                                         }
263                                 }
264
265                                 /* Free resource */
266                                 tcore_at_tok_free(tokens);
267                         }
268
269                         /* Send Notification - Network identity */
270                         dbg("Network name - Long name: [%s] Short name: [%s] "
271                                 "PLMN: [%s]", identity.long_name,
272                                 identity.short_name, identity.plmn);
273
274                         result = TEL_NETWORK_RESULT_SUCCESS;
275                 }
276         }
277
278         /* Invoke callback */
279         if (resp_cb_data->cb)
280                 resp_cb_data->cb(co, (gint)result, &identity, resp_cb_data->cb_data);
281
282         /* Free resource */
283         tcore_free(identity.long_name);
284         tcore_free(identity.short_name);
285         tcore_free(identity.plmn);
286
287         /* Free callback data */
288         imc_destroy_resp_cb_data(resp_cb_data);
289 }
290
291 /*
292  * Operation - fetch_nw_name
293  *
294  * Request -
295  * AT-Command: AT+XCOPS=<Type>
296  *
297  * <type> may be
298  * 0    numeric format of network MCC/MNC (three BCD
299  *      digit country code and two/three BCD digit network code)
300  * 1    Short Name in ROM (NV-RAM)
301  * 2    Long Name in ROM (NV-RAM)
302  * 3    Short Network Operator Name (CPHS)
303  * 4    Long Network Operator Name (CPHS)
304  * 5    Short NITZ Name
305  * 6    Full NITZ Name
306  * 7    Service Provider Name
307  * 8    EONS short operator name from EF-PNN
308  * 9    EONS long operator name from EF-PNN
309  * 11   Short PLMN name (When PS or CS is registered)
310  * 12   Long PLMN name (When PS or CS is registered)
311  * 13   numeric format of network MCC/MNC even in limited service
312  *
313  * Response - Network name
314  * Success: (Multiple Single line)
315  *      +XCOPS: <type>[,<name>[,<display_condition>]]
316  *      OK
317  * Failure:
318  *      +CME ERROR: <error>
319  */
320 static TelReturn __imc_network_fetch_nw_name(CoreObject *co,
321         TcoreObjectResponseCallback cb, void *cb_data)
322 {
323         ImcRespCbData *resp_cb_data = NULL;
324         TelReturn ret;
325
326         /* Response callback data */
327         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
328
329         /* Send Request to modem */
330         ret = tcore_at_prepare_and_send_request(co,
331                 "AT+XCOPS=0;+XCOPS=5;+XCOPS=6", "+XCOPS",
332                 TCORE_AT_COMMAND_TYPE_MULTILINE,
333                 NULL,
334                 __on_response_imc_network_fetch_nw_name, resp_cb_data,
335                 on_send_imc_request, NULL);
336         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Fetch Network name");
337
338         return ret;
339 }
340
341 /* Hook functions */
342 static TcoreHookReturn on_hook_imc_set_flight_mode(CoreObject *co,
343         TcoreCommand command, const void *request, const void *user_data,
344         TcoreObjectResponseCallback cb, const void *cb_data)
345 {
346         gboolean *flight_mode = (gboolean *)request;
347
348         /*
349          * Hook Set Flight mode request.
350          *
351          * Disable Flight mode - Hook response (if success Register to Network)
352          * Enable Flight mode - return
353          */
354         if (*flight_mode != TRUE) {
355                 /* Add response hook */
356                 tcore_object_add_response_hook(co, command, request,
357                         __on_response_imc_hook_set_flight_mode, NULL);
358
359                 return TCORE_HOOK_RETURN_CONTINUE;
360         }
361
362         dbg("Flight mode - [Enabled]");
363         return TCORE_HOOK_RETURN_CONTINUE;
364 }
365
366 static TcoreHookReturn on_hook_imc_sim_status(TcorePlugin *plugin,
367         TcoreNotification command, guint data_len, void *data, void *user_data)
368 {
369         const TelSimCardStatus *sim_status = (TelSimCardStatus *)data;
370
371         tcore_check_return_value(sim_status != NULL,
372                 TCORE_HOOK_RETURN_CONTINUE);
373
374         /*
375          * Hook SIM initialization Notification
376          *
377          * SIM INIT complete - Attach to network (Register to network)
378          * SIM INIT not complete - return
379          */
380         if (*sim_status == TEL_SIM_STATUS_SIM_INIT_COMPLETED) {
381                 CoreObject *co = (CoreObject *)user_data;
382                 dbg("SIM Initialized!!! Attach to Network");
383
384                 tcore_check_return_value_assert(co != NULL,
385                         TCORE_HOOK_RETURN_CONTINUE);
386
387                 /*
388                  * TODO - Check for selection_mode
389                  *      Need to check if it is Manual or Automatic and based on
390                  *      that need to initiate Network Registratin accordingly.
391                  */
392                 __imc_network_register_to_network(co);
393
394                 return TCORE_HOOK_RETURN_CONTINUE;
395         }
396
397         dbg("SIM not yet initialized - SIM Status: [%d]", *sim_status);
398         return TCORE_HOOK_RETURN_CONTINUE;
399 }
400
401 /* Notification callbacks */
402 /*
403  * Notification: +CREG: <stat>[,<lac>,<ci>[,<AcT>]]
404  *
405  * Possible values of <stat> can be
406  * 0    Not registered, ME is not currently searching
407  *      a new operator to register to
408  * 1    Registered, home network
409  * 2    Not registered, but ME is currently searching
410  *      a new operator to register
411  * 3    Registration denied
412  * 4    Unknown
413  * 5    Registered, in roaming
414  *
415  * <lac>
416  *      string type; two byte location area code in
417  *      hexadecimal format (e.g. 00C3)
418  *
419  * <ci>
420  *      string type; four byte cell ID in hexadecimal
421  *      format (e.g. 0000A13F)
422  *
423  * <ACT>
424  * 0    GSM
425  * 2    UTRAN
426  * 3    GSM w/EGPRS
427  * 4    UTRAN w/HSDPA
428  * 5    UTRAN w/HSUPA
429  * 6    UTRAN w/HSDPA and HSUPA
430  */
431 static gboolean on_notification_imc_cs_network_info(CoreObject *co,
432         const void *event_info, void *user_data)
433 {
434         GSList *lines = NULL;
435         gchar *line = NULL;
436
437         dbg("Network notification - CS network info: [+CREG]");
438
439         lines = (GSList *)event_info;
440         if (g_slist_length(lines) != 1) {
441                 err("+CREG unsolicited message expected to be Single line "
442                         "but received multiple lines");
443                 return TRUE;
444         }
445
446         line = (gchar *) (lines->data);
447         if (line != NULL) {
448                 TelNetworkRegStatusInfo registration_status = {0, };
449                 TelNetworkCellInfo cell_info = {0, };
450                 GSList *tokens = NULL;
451                 gchar *token_str;
452                 guint stat = 0, act = 0, lac = 0, ci = 0;
453                 gboolean roam_state = FALSE;
454
455                 /*
456                  * Tokenize
457                  *
458                  * +CREG: <stat>[,<lac>,<ci>[,<AcT>]]
459                  */
460                 tokens = tcore_at_tok_new(line);
461                 if (g_slist_length(tokens) < 1) {
462                         err("Invalid notification message");
463                         goto out;
464                 }
465
466                 /* <stat> */
467                 if ((token_str = g_slist_nth_data(tokens, 0)) == NULL) {
468                         err("No <stat> in +CREG");
469                         goto out;
470                 }
471                 stat = __imc_network_map_stat(atoi(token_str));
472                 (void)tcore_network_set_cs_reg_status(co, stat);
473
474                 /* <lac> */
475                 if ((token_str = g_slist_nth_data(tokens, 1))) {
476                         token_str = tcore_at_tok_extract((const gchar *)token_str);
477
478                         lac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
479
480                         /* Update Location Area Code (lac) information */
481                         (void)tcore_network_set_lac(co, lac);
482
483                         tcore_free(token_str);
484                 } else {
485                         dbg("No <lac> in +CREG");
486                         (void)tcore_network_get_lac(co, &lac);
487                 }
488
489                 /* <ci> */
490                 if ((token_str = g_slist_nth_data(tokens, 2))) {
491                         token_str = tcore_at_tok_extract((const gchar *)token_str);
492
493                         ci = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
494
495                         /* Update Cell ID (ci) information */
496                         (void)tcore_network_set_cell_id(co, ci);
497
498                         tcore_free(token_str);
499                 } else {
500                         dbg("No <ci> in +CREG");
501                         (void)tcore_network_get_cell_id(co, &ci);
502                 }
503
504                 /* <AcT> */
505                 if ((token_str = g_slist_nth_data(tokens, 3))) {
506                         act = __imc_network_map_act(atoi(token_str));
507                         (void)tcore_network_set_access_technology(co, act);
508                 } else {
509                         dbg("No <AcT> in +CREG");
510                         (void)tcore_network_get_access_technology(co, &act);
511                 }
512                 dbg("<stat>: %d <lac>: 0x%x <ci>: 0x%x <AcT>: %d", stat, lac, ci, act);
513
514                 /* Send Notification - Network (CS) Registration status */
515                 registration_status.cs_status = stat;
516                 registration_status.act = act;
517                 (void)tcore_network_get_ps_reg_status(co, &registration_status.ps_status);
518
519                 tcore_object_send_notification(co,
520                         TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
521                         sizeof(TelNetworkRegStatusInfo), &registration_status);
522
523                 switch (stat) {
524                 case TEL_NETWORK_REG_STATUS_ROAMING:
525                         roam_state = TRUE; // no break
526                 case TEL_NETWORK_REG_STATUS_REGISTERED:
527                         /* Fetch Network name - Internal request */
528                         (void)__imc_network_fetch_nw_name(co,
529                                 __on_response_imc_network_fetch_nw_name_internal, NULL);
530                 break;
531                 default:
532                 break;
533                 }
534
535                 /* Set Roaming state */
536                 tcore_network_set_roam_state(co, roam_state);
537
538                 /* Send Notification - Cell info */
539                 cell_info.lac = (gint)lac;
540                 cell_info.cell_id = (gint)ci;
541                 (void)tcore_network_get_rac(co, &cell_info.rac);
542
543                 tcore_object_send_notification(co,
544                         TCORE_NOTIFICATION_NETWORK_LOCATION_CELLINFO,
545                         sizeof(TelNetworkCellInfo), &cell_info);
546
547 out:
548                 /* Free resource */
549                 tcore_at_tok_free(tokens);
550         }
551
552         return TRUE;
553 }
554
555 /*
556  * Notification: +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]]
557  *
558  * Possible values of <stat> can be
559  * 0    Not registered, ME is not currently searching a
560  *      new operator to register to
561  * 1    Registered, home network
562  * 2    Not registered, but ME is currently searching a
563  *      new operator to register
564  * 3    Registration denied
565  * 4    Unknown
566  * 5    Registered, in roaming
567  *
568  * <lac>
569  *      string type; two byte location area code in
570  *      hexadecimal format (e.g. 00C3)
571  *
572  * <ci>
573  *      string type; four byte cell ID in hexadecimal
574  *      format (e.g. 0000A13F)
575  *
576  * <ACT>
577  * 0    GSM
578  * 2    UTRAN
579  * 3    GSM w/EGPRS
580  * 4    UTRAN w/HSDPA
581  * 5    UTRAN w/HSUPA
582  * 6    UTRAN w/HSDPA and HSUPA
583  *
584  * <rac>:
585  *      string type; one byte routing area code in hexadecimal format
586  */
587 static gboolean on_notification_imc_ps_network_info(CoreObject *co,
588         const void *event_info, void *user_data)
589 {
590         GSList *lines = NULL;
591         gchar *line = NULL;
592
593         dbg("Network notification - PS network info: [+CGREG]");
594
595         lines = (GSList *)event_info;
596         if (g_slist_length(lines) != 1) {
597                 err("+CGREG unsolicited message expected to be Single line "
598                         "but received multiple lines");
599                 return TRUE;
600         }
601
602         line = (gchar *) (lines->data);
603         if (line != NULL) {
604                 TelNetworkRegStatusInfo registration_status = {0, };
605                 TelNetworkCellInfo cell_info = {0, };
606                 GSList *tokens = NULL;
607                 gchar *token_str;
608                 guint stat = 0, act = 0, lac = 0, ci = 0, rac = 0;
609                 gboolean roam_state = FALSE;
610
611                 /*
612                  * Tokenize
613                  *
614                  * +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]]
615                  */
616                 tokens = tcore_at_tok_new(line);
617                 if (g_slist_length(tokens) < 1) {
618                         err("Invalid notification message");
619                         goto out;
620                 }
621
622                 /* <stat> */
623                 if ((token_str = g_slist_nth_data(tokens, 0)) == NULL) {
624                         err("No <stat> in +CGREG");
625                         goto out;
626                 }
627                 stat = __imc_network_map_stat(atoi(token_str));
628                 (void)tcore_network_set_ps_reg_status(co, stat);
629
630                 /* <lac> */
631                 if ((token_str = g_slist_nth_data(tokens, 1))) {
632                         token_str = tcore_at_tok_extract((const gchar *)token_str);
633
634                         lac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
635
636                         /* Update Location Area Code (lac) information */
637                         (void)tcore_network_set_lac(co, lac);
638
639                         tcore_free(token_str);
640                 } else {
641                         dbg("No <lac> in +CGREG");
642                         (void)tcore_network_get_lac(co, &lac);
643                 }
644
645                 /* <ci> */
646                 if ((token_str = g_slist_nth_data(tokens, 2))) {
647                         token_str = tcore_at_tok_extract((const gchar *)token_str);
648
649                         ci = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
650
651                         /* Update Cell ID (ci) information */
652                         (void)tcore_network_set_cell_id(co, ci);
653
654                         tcore_free(token_str);
655                 } else {
656                         dbg("No <ci> in +CGREG");
657                         (void)tcore_network_get_cell_id(co, &ci);
658                 }
659
660                 /* <AcT> */
661                 if ((token_str = g_slist_nth_data(tokens, 3))) {
662                         act = __imc_network_map_act(atoi(token_str));
663                         (void)tcore_network_set_access_technology(co, act);
664                 } else {
665                         dbg("No <AcT> in +CGREG");
666                         (void)tcore_network_get_access_technology(co, &act);
667                 }
668
669                 /* <rac> */
670                 if ((token_str = g_slist_nth_data(tokens, 4))) {
671                         token_str = tcore_at_tok_extract((const gchar *)token_str);
672
673                         rac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
674
675                         /* Update Routing Area Code (rac) information */
676                         (void)tcore_network_set_rac(co, rac);
677
678                         tcore_free(token_str);
679                 } else {
680                         err("No <ci> in +CGREG");
681                         (void)tcore_network_get_rac(co, &rac);
682                 }
683                 dbg("<stat>: %d <lac>: 0x%x <ci>: 0x%x <AcT>: %d <rac>: 0x%x", stat, lac, ci, act, rac);
684
685                 /* Send Notification - Network (PS) Registration status */
686                 registration_status.ps_status = stat;
687                 registration_status.act = act;
688                 (void)tcore_network_get_cs_reg_status(co, &registration_status.cs_status);
689
690                 tcore_object_send_notification(co,
691                         TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
692                         sizeof(TelNetworkRegStatusInfo), &registration_status);
693
694                 /* Set Roaming state */
695                 if (registration_status.ps_status == TEL_NETWORK_REG_STATUS_ROAMING)
696                         roam_state = TRUE;
697
698                 tcore_network_set_roam_state(co, roam_state);
699
700                 /* Send Notification - Cell info */
701                 cell_info.lac = lac;
702                 cell_info.cell_id = ci;
703                 cell_info.rac = rac;
704                 tcore_object_send_notification(co,
705                         TCORE_NOTIFICATION_NETWORK_LOCATION_CELLINFO,
706                         sizeof(TelNetworkCellInfo), &cell_info);
707
708 out:
709                 /* Free resource */
710                 tcore_at_tok_free(tokens);
711         }
712
713         return TRUE;
714 }
715
716 /*
717  * Notification: +XNITZINFO: <fullname>,<shortname>,<LTZ>,<UT>,<DST>
718  *
719  * <longname>
720  *      string type; Network name in long alphanumeric format.
721  *
722  * <shortname>
723  *      string type; Network name in short alphanumeric format.
724  *
725  * <LTZ>
726  *      Local Time Zone; represented as 1 unit = 15 minutes.
727  *
728  * <UT>
729  *      string type value; Universal Time
730  *      format is "yy/MM/dd,hh:mm:ss",
731  *      wherein characters indicates year, month, day, hour,
732  *      minutes, seconds.
733  * <DST>
734  *      Daylight Saving Time; represented in hours.
735  */
736 static gboolean on_notification_imc_network_time_info(CoreObject *co,
737         const void *event_info, void *user_data)
738 {
739         GSList *lines = NULL;
740         gchar *line = NULL;
741
742         dbg("Network notification - Time info: [+XNITZINFO]");
743
744         lines = (GSList *)event_info;
745         if (g_slist_length(lines) != 1) {
746                 err("+XNITZINFO unsolicited message expected to be Single line "
747                         "but received multiple lines");
748                 return TRUE;
749         }
750
751         line = (gchar *)lines->data;
752         if (line != NULL) {
753                 GSList *tokens = NULL;
754                 TelNetworkNitzInfoNoti nitz_info = {0, };
755                 gchar *fullname, *shortname;
756                 gchar *ltz, *time;
757                 gchar tmp_time[8] = {0};
758                 gchar *dstoff;
759
760                 /*
761                  * Tokenize
762                  *
763                  * +XNITZINFO: <fullname>,<shortname>,<LTZ>,<UT>,<DST>
764                  */
765                 tokens = tcore_at_tok_new(line);
766
767                 /* <fullname> */
768                 if ((fullname = tcore_at_tok_nth(tokens, 1))) {
769                         if (strlen(fullname) > 0) {
770                                 fullname = tcore_at_tok_extract((const char *)fullname);
771
772                                 /* Update Long name */
773                                 tcore_network_set_long_name(co, fullname);
774
775                                 tcore_free(fullname);
776                         }
777                 }
778
779                 /* <shortname> */
780                 if ((shortname = tcore_at_tok_nth(tokens, 1))) {
781                         if (strlen(shortname) > 0) {
782                                 shortname = tcore_at_tok_extract((const char *)shortname);
783
784                                 /* Update Short name */
785                                 tcore_network_set_short_name(co, shortname);
786
787                                 tcore_free(shortname);
788                         }
789                 }
790
791                 /* <LTZ> */
792                 if ((ltz = g_slist_nth_data(tokens, 2)))
793                         nitz_info.gmtoff = atoi(ltz) * 15;/* gmtoff in minutes */
794
795                 if ((time = g_slist_nth_data(tokens, 3))
796                                 && (strlen(time) > 18)) {
797                         /* (time + 1) - Skip past initial quote (") */
798                         g_strlcpy(tmp_time, time + 1, 2+1);
799                         nitz_info.year = atoi(tmp_time);
800
801                         /* skip slash (/) after year param */
802                         g_strlcpy(tmp_time, time + 4, 2+1);
803                         nitz_info.month = atoi(tmp_time);
804
805                         /* skip past slash (/) after month param */
806                         g_strlcpy(tmp_time, time + 7, 2+1);
807                         nitz_info.day = atoi(tmp_time);
808
809                         /* skip past comma (,) after day param */
810                         g_strlcpy(tmp_time, time + 10, 2+1);
811                         nitz_info.hour = atoi(tmp_time);
812
813                         /* skip past colon (:) after hour param */
814                         g_strlcpy(tmp_time, time + 13, 2+1);
815                         nitz_info.minute = atoi(tmp_time);
816
817                          /* skip past colon (:) after minute param */
818                          g_strlcpy(tmp_time, time + 16, 2+1);
819                         nitz_info.second = atoi(tmp_time);
820                 }
821
822                 /* <DST> */
823                 if ((dstoff = g_slist_nth_data(tokens, 4))) {
824                         nitz_info.dstoff = atoi(dstoff);
825                         nitz_info.isdst = TRUE;
826                 }
827
828                 /* Get PLMN */
829                 tcore_network_get_plmn(co, &nitz_info.plmn);
830
831                 /* Send Notification - Network time info */
832                 tcore_object_send_notification(co,
833                         TCORE_NOTIFICATION_NETWORK_TIMEINFO,
834                         sizeof(TelNetworkNitzInfoNoti), &nitz_info);
835
836                 /* Free resource */
837                 tcore_free(nitz_info.plmn);
838                 tcore_at_tok_free(tokens);
839         }
840
841         return TRUE;
842 }
843
844 /*
845  * Notification:
846  *      +XCIEV: <rssi>,
847  * or
848  *      +XCIEV:,<battery_level>
849  *
850  * 'Radio Signal Strength' <rssi> can have the values
851  * 0    -107 dBm or less or unknown
852  * 1    -99 dBm or less
853  * 2    -91 dBm or less
854  * 3    -83 dBm or less
855  * 4    -75 dBm or less
856  * 5    -67 dBm or less
857  * 6    -59 dBm or less
858  * 7    -51 dBm or less
859  *
860  * 'Battery Level' <battery_level> can have the values
861  * 0    0 % <= level < 5 %
862  * 1    5 % <= level < 15 %
863  * 2    15 % <= level < 25 %
864  * 3    25 % <= level < 40 %
865  * 4    40 % <= level < 55 %
866  * 5    55 % <= level < 70 %
867  * 6    70 % <= level < 85 %
868  * 7    85 % <= level <= 100 %
869  *
870  * NOTE:
871  *      <battery_level> is not consider for
872  *      TCORE_NOTIFICATION_NETWORK_RSSI notification
873  */
874 static gboolean on_notification_imc_network_rssi(CoreObject *co,
875         const void *event_info, void *user_data)
876 {
877         GSList *lines = NULL;
878         gchar *line = NULL;
879
880         dbg("Network notification - Icon (rssi) info: [+XCIEV]");
881
882         lines = (GSList *)event_info;
883         if (g_slist_length(lines) != 1) {
884                 err("+XCIEV unsolicited message expected to be Single line "
885                         "but received multiple lines");
886                 return TRUE;
887         }
888
889         line = (gchar *)lines->data;
890         if (line != NULL) {
891                 GSList *tokens = NULL;
892                 gchar *rssi_token;
893
894                 /*
895                  * Tokenize
896                  *
897                  * +XCIEV: <rssi>,
898                  */
899                 tokens = tcore_at_tok_new(line);
900
901                 rssi_token = (gchar *)g_slist_nth_data(tokens, 0);
902                 if (rssi_token && strlen(rssi_token)) {
903                         guint rssi_bar = atoi(rssi_token);
904                         dbg("RSSI Level: [%d]", rssi_bar);
905
906                         /* Send Notification - Network Rssi */
907                         tcore_object_send_notification(co,
908                                 TCORE_NOTIFICATION_NETWORK_RSSI,
909                                 sizeof(guint), &rssi_bar);
910                 }
911
912                 /* Free resource */
913                 tcore_at_tok_free(tokens);
914         }
915
916         return TRUE;
917 }
918
919 /* Network Responses */
920
921 static void on_response_imc_network_search(TcorePending *p,
922         guint data_len, const void *data, void *user_data)
923 {
924         const TcoreAtResponse *at_resp = data;
925         CoreObject *co = tcore_pending_ref_core_object(p);
926         CustomData *custom_data;
927
928         ImcRespCbData *resp_cb_data = user_data;
929         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
930         TelNetworkPlmnList plmn_list = {0, };
931         guint num_network_avail = 0;
932         guint count;
933         GSList *tokens = NULL;
934
935         dbg("Enter");
936         tcore_check_return_assert(co != NULL);
937         tcore_check_return_assert(resp_cb_data != NULL);
938
939         custom_data = tcore_object_ref_user_data(co);
940         tcore_check_return_assert(custom_data != NULL);
941
942         if (at_resp && at_resp->success) {
943                 const gchar *line;
944                 GSList *net_token = NULL;
945                 gchar *resp;
946                 gint act;
947
948                 /* If Request is Cancelled then return back SUCCESS/SEARCH_CANCELLED */
949                 if (custom_data->search_state
950                         == IMC_NETWORK_SEARCH_STATE_CANCELLED) {
951                         dbg("Network Search has been Cancelled!!!");
952
953                         /*
954                          * TODO:
955                          *
956                          * Need to introduce new Result -
957                          *      TEL_NETWORK_RESULT_SEARCH_ABORTED/CANCELLED
958                          *
959                          * Presently sending TEL_NETWORK_RESULT_FAILURE
960                          */
961                         result = TEL_NETWORK_RESULT_FAILURE;
962
963                         goto END;
964                 }
965
966                 if (!at_resp->lines) {
967                         err("invalid response received");
968                         goto END;
969                 }
970
971                 line = (char *) at_resp->lines->data;
972                 tokens = tcore_at_tok_new(line);
973                 num_network_avail = g_slist_length(tokens);
974                 if (num_network_avail < 1) {
975                         err("invalid message");
976                         goto END;
977                 }
978
979                 plmn_list.network_list = tcore_malloc0(sizeof(TelNetworkInfo) * num_network_avail);
980                 dbg("RESPONSE OK");
981                 plmn_list.count = 0;
982                 for (count = 0; count < num_network_avail; count++) {
983
984                         net_token = tcore_at_tok_new(g_slist_nth_data(tokens, count));
985                         if (NULL == net_token)
986                                 continue;
987
988                         resp = tcore_at_tok_nth(net_token, 0);
989                         if (resp != NULL) {
990                                 plmn_list.network_list[count].plmn_status = atoi(resp);
991                                 dbg("status[%d]", plmn_list.network_list[count].plmn_status);
992                         }
993
994                         if ((resp = tcore_at_tok_nth(net_token, 1))) {
995                                 /* Long Alpha name */
996                                 dbg("long alpha name[%s]", resp);
997                                 plmn_list.network_list[count].network_identity.long_name =
998                                         tcore_at_tok_extract(resp);
999                         }
1000
1001                         if ((resp = tcore_at_tok_nth(net_token, 2))) {
1002                                 /* Short Alpha name */
1003                                 dbg("Short Alpha name[%s]", resp);
1004                                 plmn_list.network_list[count].network_identity.short_name =
1005                                         tcore_at_tok_extract(resp);
1006                         }
1007
1008                         /* PLMN ID */
1009                         if ((resp = tcore_at_tok_nth(net_token, 3))) {
1010                                 dbg("PLMN ID[%s]", resp);
1011                                 plmn_list.network_list[count].network_identity.plmn =
1012                                         tcore_at_tok_extract(resp);
1013                         }
1014
1015                         /* Parse Access Technology */
1016                         if ((resp = tcore_at_tok_nth(tokens, 4))) {
1017                                         act = atoi(resp);
1018                                         if (0 == act)
1019                                                 plmn_list.network_list[count].act = TEL_NETWORK_ACT_GSM;
1020                                         else if (2 == act)
1021                                                 plmn_list.network_list[count].act = TEL_NETWORK_ACT_UMTS;
1022                                 }
1023
1024                         dbg("Operator [%d] :: status = %d, long_name = %s, short_name = %s plmn = %s, AcT=%d",
1025                                         plmn_list.count,
1026                                         plmn_list.network_list[count].plmn_status,
1027                                         plmn_list.network_list[count].network_identity.long_name,
1028                                         plmn_list.network_list[count].network_identity.short_name,
1029                                         plmn_list.network_list[count].network_identity.plmn,
1030                                         plmn_list.network_list[count].act);
1031
1032                         plmn_list.count ++;
1033                         tcore_at_tok_free(net_token);
1034                 }
1035                 result = TEL_NETWORK_RESULT_SUCCESS;
1036         } else {
1037                 err("RESPONSE NOK");
1038                 if (at_resp->lines)
1039                         err("CME Error[%s]",(char *)at_resp->lines->data);
1040         }
1041
1042 END:
1043         dbg("Network search : [%s]",
1044                         (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1045
1046         /* Update Search state */
1047         custom_data->search_state = IMC_NETWORK_SEARCH_STATE_NO_SEARCH;
1048
1049         /* Invoke callback */
1050         if (resp_cb_data->cb)
1051                 resp_cb_data->cb(co, (gint)result, &plmn_list, resp_cb_data->cb_data);
1052
1053         imc_destroy_resp_cb_data(resp_cb_data);
1054
1055         /* Free resources*/
1056         for (count = 0; count < num_network_avail; count++) {
1057                 g_free(plmn_list.network_list[count].network_identity.long_name);
1058                 g_free(plmn_list.network_list[count].network_identity.short_name);
1059                 g_free(plmn_list.network_list[count].network_identity.plmn);
1060         }
1061
1062         tcore_free(plmn_list.network_list);
1063         tcore_at_tok_free(tokens);
1064 }
1065
1066 static gboolean on_response_imc_network_cancel_search(gpointer data)
1067 {
1068         ImcRespCbData *resp_cb_data = data;
1069         ImcNetworkCancelSearch *cancel_search =
1070                 (ImcNetworkCancelSearch *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1071
1072         /* Invoke callback */
1073         if (resp_cb_data->cb)
1074                 resp_cb_data->cb(cancel_search->co, (gint)cancel_search->result,
1075                         NULL, resp_cb_data->cb_data);
1076
1077         imc_destroy_resp_cb_data(resp_cb_data);
1078
1079         /* To stop the cycle, need to return FALSE */
1080         return FALSE;
1081 }
1082
1083 static void on_response_imc_network_get_selection_mode(TcorePending *p,
1084         guint data_len, const void *data, void *user_data)
1085 {
1086         const TcoreAtResponse *at_resp = data;
1087         CoreObject *co = tcore_pending_ref_core_object(p);
1088         ImcRespCbData *resp_cb_data = user_data;
1089         TelNetworkSelectionMode selection_mode = -1;
1090         GSList *tokens = NULL;
1091
1092         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1093         dbg("Enter");
1094
1095         tcore_check_return_assert(co != NULL);
1096         tcore_check_return_assert(resp_cb_data != NULL);
1097
1098         if (at_resp && at_resp->success) {
1099                 const gchar *line;
1100                 gint mode;
1101
1102                 if (!at_resp->lines) {
1103                         err("invalid response received");
1104                         goto END;
1105                 }
1106
1107                 line = (char *) at_resp->lines->data;
1108                 tokens = tcore_at_tok_new(line);
1109                 if (g_slist_length(tokens) < 1) {
1110                         msg("invalid message");
1111                         goto END;
1112                 }
1113                 dbg("RESPONSE OK");
1114
1115                 mode = atoi(tcore_at_tok_nth(tokens, 0));
1116                 if (mode == 0)
1117                         selection_mode = TEL_NETWORK_SELECTION_MODE_AUTOMATIC;
1118                 else if (mode == 1)
1119                         selection_mode = TEL_NETWORK_SELECTION_MODE_MANUAL;
1120
1121                 result = TEL_NETWORK_RESULT_SUCCESS;
1122                 dbg("selection mode[%d]", selection_mode);
1123
1124         } else {
1125                 err("RESPONSE NOK");
1126         }
1127
1128 END:
1129         dbg("Get selection mode : [%s]",
1130                         (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1131         /* Invoke callback */
1132         if (resp_cb_data->cb)
1133                 resp_cb_data->cb(co, (gint)result, &selection_mode, resp_cb_data->cb_data);
1134
1135         /* Free callback data */
1136         imc_destroy_resp_cb_data(resp_cb_data);
1137         /* Free resource*/
1138         tcore_at_tok_free(tokens);
1139 }
1140
1141 static void on_response_imc_network_default(TcorePending *p,
1142         guint data_len, const void *data, void *user_data)
1143 {
1144         const TcoreAtResponse *at_resp = data;
1145         CoreObject *co = tcore_pending_ref_core_object(p);
1146         ImcRespCbData *resp_cb_data = user_data;
1147         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1148
1149         dbg("Enter");
1150         tcore_check_return_assert(co != NULL);
1151         tcore_check_return_assert(resp_cb_data != NULL);
1152
1153         if (at_resp && at_resp->success) {
1154                 dbg("RESPONSE OK");
1155                 result = TEL_NETWORK_RESULT_SUCCESS;
1156         } else {
1157                 err("RESPONSE NOK");
1158                 if (at_resp->lines)
1159                         err("CME Error[%s]",(char *)at_resp->lines->data);
1160         }
1161
1162         /* Invoke callback */
1163         if (resp_cb_data->cb)
1164                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1165
1166         imc_destroy_resp_cb_data(resp_cb_data);
1167 }
1168
1169
1170 static void on_response_imc_network_get_mode(TcorePending *p,
1171         guint data_len, const void *data, void *user_data)
1172 {
1173         const TcoreAtResponse *at_resp = data;
1174         CoreObject *co = tcore_pending_ref_core_object(p);
1175         ImcRespCbData *resp_cb_data = user_data;
1176         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1177         TelNetworkMode mode = -1;
1178         GSList *tokens = NULL;
1179
1180         dbg("Enter");
1181         tcore_check_return_assert(co != NULL);
1182         tcore_check_return_assert(resp_cb_data != NULL);
1183
1184         if (at_resp && at_resp->success) {
1185                 const gchar *line;
1186                 gint net_mode;
1187
1188                 if (!at_resp->lines) {
1189                         err("invalid response received");
1190                         goto END;
1191                 }
1192
1193                 line = (char *) at_resp->lines->data;
1194                 tokens = tcore_at_tok_new(line);
1195                 if (g_slist_length(tokens) < 1) {
1196                         err("invalid message");
1197                         goto END;
1198                 }
1199
1200                 dbg("RESPONSE OK");
1201                 net_mode = atoi(tcore_at_tok_nth(tokens, 0));
1202                 dbg("mode = %d", net_mode);
1203
1204                 switch(net_mode) {
1205                 case 0:
1206                         mode = TEL_NETWORK_MODE_2G;
1207                         break;
1208                 case 1:
1209                         mode = TEL_NETWORK_MODE_AUTO;
1210                         break;
1211                 case 2:
1212                         mode = TEL_NETWORK_MODE_3G;
1213                         break;
1214                 default:
1215                         err("Unsupported  mode [%d]", net_mode);
1216                         goto END;
1217                 }
1218                 result = TEL_NETWORK_RESULT_SUCCESS;
1219         } else {
1220                 err("RESPONSE NOK");
1221         }
1222 END:
1223         /* Invoke callback */
1224         if (resp_cb_data->cb)
1225                 resp_cb_data->cb(co, (gint)result, &mode, resp_cb_data->cb_data);
1226
1227         /* Free callback data */
1228         imc_destroy_resp_cb_data(resp_cb_data);
1229         /* Free resource*/
1230         tcore_at_tok_free(tokens);
1231 }
1232
1233 static void on_response_imc_network_get_preferred_plmn(TcorePending *p,
1234         guint data_len, const void *data, void *user_data)
1235 {
1236         const TcoreAtResponse *at_resp = data;
1237         CoreObject *co = tcore_pending_ref_core_object(p);
1238         ImcRespCbData *resp_cb_data = user_data;
1239         TelNetworkPreferredPlmnList plmn_list = {0,};
1240         guint count = 0, total_lines = 0;
1241         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1242         dbg("Enter");
1243
1244         tcore_check_return_assert(co != NULL);
1245         tcore_check_return_assert(resp_cb_data != NULL);
1246
1247         if (at_resp && at_resp->success) {
1248                 GSList *tokens;
1249                 gchar *resp;
1250                 gchar *line;
1251                 gboolean gsm_act2 = FALSE, gsm_compact_act2 = FALSE;
1252                 gboolean utran_act2 = FALSE;
1253
1254                 if (!at_resp->lines) {
1255                         err("invalid response received");
1256                         goto END;
1257                 }
1258
1259                 total_lines = g_slist_length(at_resp->lines);
1260                 if (total_lines < 1) {
1261                         msg("invalid message");
1262                         goto END;
1263                 }
1264
1265                 dbg("RESPONSE OK");
1266                 result = TEL_NETWORK_RESULT_SUCCESS;
1267
1268                 plmn_list.list = tcore_malloc0(sizeof(TelNetworkPreferredPlmnInfo) * total_lines);
1269                 plmn_list.count = 0;
1270
1271                 for (count = 0; count < total_lines; count++) {
1272                         /* Take each line response at a time & parse it */
1273                         line = tcore_at_tok_nth(at_resp->lines, count);
1274                         tokens = tcore_at_tok_new(line);
1275
1276                         /*Index */
1277                         if ((resp = tcore_at_tok_nth(tokens, 0))) {
1278                                 plmn_list.list[count].index = atoi(resp);
1279                         }
1280
1281                         /* PLMN ID */
1282                         if ((resp = tcore_at_tok_nth(tokens, 2))) {
1283                                 plmn_list.list[count].plmn = tcore_at_tok_extract(resp);
1284                         }
1285
1286                         /*GSM_AcT1 */
1287                         if ((resp = tcore_at_tok_nth(tokens, 3))) {
1288                                 gsm_act2 = atoi(resp);
1289                         }
1290
1291                         /*GSM_Compact_AcT2 */
1292                         if ((resp = tcore_at_tok_nth(tokens, 4))) {
1293                                 gsm_compact_act2 = atoi(resp);
1294                         }
1295
1296                         /*UTRAN_AcT2 */
1297                         if ((resp = tcore_at_tok_nth(tokens, 5))) {
1298                                 utran_act2 = atoi(resp);
1299                         }
1300
1301                         if (gsm_act2)
1302                                 plmn_list.list[count].act = TEL_NETWORK_ACT_UMTS;
1303                         else if (utran_act2 || gsm_compact_act2)
1304                                 plmn_list.list[count].act = TEL_NETWORK_ACT_GSM;
1305
1306                         /* free tokens*/
1307                         tcore_at_tok_free(tokens);
1308
1309                         dbg("index[%d], plmn[%s], act[%d]",
1310                                 plmn_list.list[count].index,
1311                                 plmn_list.list[count].plmn,
1312                                 plmn_list.list[count].act);
1313
1314                 }
1315                 plmn_list.count = count;
1316         } else {
1317                 err("RESPONSE NOK");
1318                 if (at_resp->lines)
1319                         err("CME Error[%s]",(char *)at_resp->lines->data);
1320         }
1321
1322 END:
1323         dbg("get preferred plmn : [%s]",
1324                         (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1325
1326         /* Invoke callback */
1327         if (resp_cb_data->cb)
1328                 resp_cb_data->cb(co, (gint)result, &plmn_list, resp_cb_data->cb_data);
1329
1330         /* Free callback data */
1331         imc_destroy_resp_cb_data(resp_cb_data);
1332
1333         for(count = 0; count < total_lines; count++) {
1334                 g_free(plmn_list.list[count].plmn);
1335         }
1336         tcore_free(plmn_list.list);
1337 }
1338
1339
1340 /* Network Operations */
1341 /*
1342  * Operation - set_power_status
1343  *
1344  * Request -
1345  * AT-Command: AT+XCOPS=<Type>
1346  *
1347  * <type> may be
1348  * 0    numeric format of network MCC/MNC (three BCD
1349  *      digit country code and two/three BCD digit network code)
1350  * 1    Short Name in ROM (NV-RAM)
1351  * 2    Long Name in ROM (NV-RAM)
1352  * 3    Short Network Operator Name (CPHS)
1353  * 4    Long Network Operator Name (CPHS)
1354  * 5    Short NITZ Name
1355  * 6    Full NITZ Name
1356  * 7    Service Provider Name
1357  * 8    EONS short operator name from EF-PNN
1358  * 9    EONS long operator name from EF-PNN
1359  * 11   Short PLMN name (When PS or CS is registered)
1360  * 12   Long PLMN name (When PS or CS is registered)
1361  * 13   numeric format of network MCC/MNC even in limited service
1362  *
1363  * Response - Network name
1364  * Success: (Multiple Single line)
1365  *      +XCOPS: <type>[,<name>[,<display_condition>]]
1366  *      OK
1367  * Failure:
1368  *      +CME ERROR: <error>
1369  */
1370 static TelReturn imc_network_get_identity_info(CoreObject *co,
1371         TcoreObjectResponseCallback cb, void *cb_data)
1372 {
1373         return __imc_network_fetch_nw_name(co, cb, cb_data);
1374 }
1375
1376 /*
1377  * Operation -  network search
1378  * Request -
1379  * AT-Command: AT+COPS=?
1380  *
1381  * Response -
1382  * Success: (Single line)
1383  * +COPS: [list of supported (<stat>,long alphanumeric <oper>
1384  * ,short alphanumeric <oper>,numeric <oper>[,< AcT>]
1385  * [,,(list of supported <mode>s),(list of supported <format>s)]
1386
1387  * <format>
1388  * describes the format in which operator name is to be displayed. Different values of <format> can be:
1389  * 0 <oper> format presentations are set to long alphanumeric. If Network name not available it displays
1390  *   combination of Mcc and MNC in string format.
1391  * 1 <oper> format presentation is set to short alphanumeric.
1392  * 2 <oper> format presentations set to numeric.
1393  * <oper>:
1394  * string type given in format <format>; this field may be up to 16 character long for long alphanumeric format, up
1395  * to 8 characters for short alphanumeric format and 5 Characters long for numeric format (MCC/MNC codes)
1396  * <stat>:
1397  * describes the status of the network. It is one of the response parameter for test command.
1398  * 0 Unknown Networks
1399  * 1 Network Available
1400  * 2 Current
1401  * 3 Forbidden Network
1402  * <AcT>
1403  * indicates the radio access technology and values can be:
1404  * 0 GSM
1405  * 2 UMTS
1406  * OK
1407  * Failure:
1408  * +CME ERROR: <error>
1409  */
1410
1411 static TelReturn imc_network_search(CoreObject *co,
1412         TcoreObjectResponseCallback cb, void *cb_data)
1413 {
1414         ImcRespCbData *resp_cb_data;
1415         CustomData *custom_data;
1416         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1417
1418         custom_data = tcore_object_ref_user_data(co);
1419         if (custom_data->search_state
1420                         == IMC_NETWORK_SEARCH_STATE_IN_PROGRESS) {
1421                 warn("Network Search: [ALREADY IN PROGRESS]");
1422                 return TEL_RETURN_FAILURE;
1423         }
1424
1425         /* Response callback data */
1426         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1427
1428         /* Send Request to modem */
1429         ret = tcore_at_prepare_and_send_request_ex(co,
1430                 "AT+COPS=?", "+COPS",
1431                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1432                 TCORE_PENDING_PRIORITY_DEFAULT,
1433                 NULL,
1434                 on_response_imc_network_search, resp_cb_data,
1435                 on_send_imc_request, NULL,
1436                 0, NULL, NULL,
1437                 FALSE, TRUE);
1438         if (ret != TEL_RETURN_SUCCESS) {
1439                 err("Failed to process request - [%s]", "Network Search");
1440                 imc_destroy_resp_cb_data(resp_cb_data);
1441         }
1442         else {
1443                 custom_data->search_state = IMC_NETWORK_SEARCH_STATE_IN_PROGRESS;
1444                 dbg("Search State: [IN PROGRESS]");
1445         }
1446
1447         return ret;
1448 }
1449
1450 static TelReturn imc_network_cancel_search(CoreObject *co,
1451         TcoreObjectResponseCallback cb, void *cb_data)
1452 {
1453         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1454         ImcRespCbData *resp_cb_data;
1455         CustomData *custom_data;
1456         ImcNetworkCancelSearch cancel_search = {0, };
1457
1458         custom_data = tcore_object_ref_user_data(co);
1459         if (custom_data->search_state
1460                         == IMC_NETWORK_SEARCH_STATE_IN_PROGRESS) {
1461                 dbg("Search in Progress...");
1462
1463                 /* Send Request to modem */
1464                 ret = tcore_at_prepare_and_send_request_ex(co,
1465                         "\e", NULL,
1466                         TCORE_AT_COMMAND_TYPE_NO_RESULT,
1467                         TCORE_PENDING_PRIORITY_IMMEDIATELY,
1468                         NULL,
1469                         NULL, NULL,
1470                         on_send_imc_request, NULL,
1471                         0, NULL, NULL,
1472                         TRUE, FALSE);
1473                 if (ret != TEL_RETURN_SUCCESS) {
1474                         err("Failed to process request - [%s]", "Cancel network search");
1475                         goto out;
1476                 }
1477                 else {
1478                         custom_data->search_state = IMC_NETWORK_SEARCH_STATE_CANCELLED;
1479                         dbg("Search State: [CANCELLED]");
1480                 }
1481         }
1482         else {
1483                 dbg("No Search in Progress...");
1484                 ret = TEL_RETURN_SUCCESS;
1485         }
1486
1487         cancel_search.co = co;
1488         cancel_search.result = TEL_NETWORK_RESULT_SUCCESS;
1489
1490         /* Response callback data */
1491         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
1492                 &cancel_search, sizeof(ImcNetworkCancelSearch));
1493
1494         /* Send response */
1495         g_idle_add(on_response_imc_network_cancel_search, (gpointer)resp_cb_data);
1496
1497 out:
1498         return ret;
1499 }
1500
1501 /*
1502  * Operation -  automatic network selection
1503  * Request -
1504  * AT-Command: AT+COPS= [<mode> [, <format> [, <oper>> [, <AcT>]]]]
1505  * where
1506  * <mode>
1507  * is used to select, whether the selection is done automatically by the ME or is forced by this command to
1508  * operator <oper> given in the format <format>.
1509  * The values of <mode> can be:
1510  * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME
1511  * 1 Manual. Other parameters like format and operator need to be passed
1512  * 2 Deregister from network
1513  * 3 It sets <format> value. In this case <format> becomes a mandatory input
1514  * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered
1515  *
1516  * Response -
1517  * Success:(No result)
1518  * OK or
1519  * +CME ERROR: <err>
1520  */
1521 static TelReturn imc_network_select_automatic(CoreObject *co,
1522         TcoreObjectResponseCallback cb, void *cb_data)
1523 {
1524         ImcRespCbData *resp_cb_data;
1525         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1526         dbg("entry");
1527
1528         /* Response callback data */
1529         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1530
1531         /* Send Request to modem */
1532         ret = tcore_at_prepare_and_send_request(co,
1533                 "AT+COPS=0", NULL,
1534                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1535                 NULL,
1536                 on_response_imc_network_default, resp_cb_data,
1537                 on_send_imc_request, NULL);
1538         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Automatic network selection");
1539
1540         return ret;
1541 }
1542
1543 /*
1544  * Operation -  manual network selection
1545  * Request -
1546  * AT-Command: AT+COPS= [<mode> [, <format> [, <oper>> [, <AcT>]]]]
1547  * where
1548  * <mode>
1549  * is used to select, whether the selection is done automatically by the ME or is forced by this command to
1550  * operator <oper> given in the format <format>.
1551  * The values of <mode> can be:
1552  * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME
1553  * 1 Manual. Other parameters like format and operator need to be passed
1554  * 2 Deregister from network
1555  * 3 It sets <format> value. In this case <format> becomes a mandatory input
1556  * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered.
1557  * <oper>
1558  * string type given in format <format>; this field may be up to 16 character long for long alphanumeric format, up
1559  * to 8 characters for short alphanumeric format and 5 Characters long for numeric format (MCC/MNC codes)
1560  * <AcT>
1561  * indicates the radio access technology and values can be:
1562  * 0 GSM
1563  * 2 UMTS
1564  *
1565  * Response -
1566  * Success:(No result)
1567  * OK or
1568  * +CME ERROR: <err>
1569  */
1570 static TelReturn imc_network_select_manual(CoreObject *co,
1571         const TelNetworkSelectManualInfo *sel_manual,
1572         TcoreObjectResponseCallback cb, void *cb_data)
1573 {
1574         ImcRespCbData *resp_cb_data;
1575         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1576         gchar *at_cmd;
1577         gint act;
1578         dbg("entry");
1579
1580         switch(sel_manual->act) {
1581         case TEL_NETWORK_ACT_GSM:
1582         case TEL_NETWORK_ACT_GPRS:
1583         case TEL_NETWORK_ACT_EGPRS:
1584                 act = 0;
1585                 break;
1586         case TEL_NETWORK_ACT_UMTS:
1587         case TEL_NETWORK_ACT_GSM_AND_UMTS:
1588         case TEL_NETWORK_ACT_HSDPA:
1589         case TEL_NETWORK_ACT_HSPA:
1590                 act = 2;
1591                 break;
1592         default:
1593                 err("unsupported AcT");
1594                 return ret;
1595         }
1596
1597         /* AT-Command */
1598         at_cmd = g_strdup_printf("AT+COPS=1,2,\"%s\",%d", sel_manual->plmn, act);
1599
1600         /* Response callback data */
1601         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1602
1603         /* Send Request to modem */
1604         ret = tcore_at_prepare_and_send_request(co,
1605                 at_cmd, NULL,
1606                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1607                 NULL,
1608                 on_response_imc_network_default, resp_cb_data,
1609                 on_send_imc_request, NULL);
1610         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Manual network selection");
1611
1612         /* Free resources*/
1613         g_free(at_cmd);
1614         return ret;
1615 }
1616
1617 /*
1618  * Operation -  get network selection mode
1619  * Request -
1620  * AT-Command: AT+COPS?
1621  *
1622  * Response -
1623  * Success: (Single line)
1624  * +COPS: <mode>[,<format>,<oper>[,< AcT>]]
1625  * <mode>
1626  * is used to select, whether the selection is done automatically by the ME or is forced by this command to
1627  * operator <oper> given in the format <format>.
1628  * The values of <mode> can be:
1629  * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME
1630  * 1 Manual. Other parameters like format and operator need to be passed
1631  * 2 Deregister from network
1632  * 3 It sets <format> value. In this case <format> becomes a mandatory input
1633  * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered
1634  * OK
1635  * Failure:
1636  * +CME ERROR: <error>
1637  */
1638 static TelReturn imc_network_get_selection_mode(CoreObject *co,
1639         TcoreObjectResponseCallback cb, void *cb_data)
1640 {
1641         ImcRespCbData *resp_cb_data;
1642         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1643
1644         /* Response callback data */
1645         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1646
1647         /* Send Request to modem */
1648         ret = tcore_at_prepare_and_send_request(co,
1649                 "AT+COPS?", "+COPS",
1650                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1651                 NULL,
1652                 on_response_imc_network_get_selection_mode, resp_cb_data,
1653                 on_send_imc_request, NULL);
1654         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get selection mode");
1655
1656         return ret;
1657 }
1658
1659 /*
1660  * Operation -  set preferred plmn
1661  * Request -
1662  * AT-Command: AT+CPOL=<index>][,<format>[,<oper>[,<GSM_AcT>,<GSM_Compact_AcT>,<UTRAN_AcT>]]]
1663  * where
1664  * <indexn> integer type; the order number of operator in the SIM/USIM preferred operator list
1665  * <format>
1666  * 0 long format alphanumeric <oper>
1667  * 1 short format alphanumeric <oper>
1668  * 2 numeric <oper>
1669  * <opern> string type; <format> indicates if the format is alphanumeric or numeric (see +COPS)
1670  * <GSM_AcTn>: GSM access technology
1671  * 0 access technology not selected
1672  * 1 access technology selected
1673  * <GSM_Compact_AcTn>: GSM compact access technology
1674  * 0 access technology not selected
1675  * 1 access technology selected
1676  * <UTRA_AcTn>: UTRA access technology
1677  * 0 access technology not selected
1678  * 1 access technology selected
1679  *
1680  * Response -
1681  * Success:(No Result)
1682  * OK
1683  * Failure:
1684  * +CME ERROR: <error>
1685  */
1686 static TelReturn imc_network_set_preferred_plmn(CoreObject *co,
1687         const TelNetworkPreferredPlmnInfo *pref_plmn,
1688         TcoreObjectResponseCallback cb, void *cb_data)
1689 {
1690         ImcRespCbData *resp_cb_data;
1691         gchar *at_cmd;
1692         gboolean gsm_act = FALSE;
1693         gboolean gsm_compact_act = FALSE;
1694         gboolean utran_act = FALSE;
1695         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1696         dbg("entry");
1697
1698         switch(pref_plmn->act) {
1699         case TEL_NETWORK_ACT_GSM:
1700         case TEL_NETWORK_ACT_GPRS:
1701         case TEL_NETWORK_ACT_EGPRS:
1702                 gsm_act = TRUE;
1703                 break;
1704         case TEL_NETWORK_ACT_UMTS:
1705         case TEL_NETWORK_ACT_HSDPA:
1706         case TEL_NETWORK_ACT_HSPA:
1707                 utran_act = TRUE;
1708                 break;
1709         case TEL_NETWORK_ACT_GSM_AND_UMTS:
1710                 gsm_act = utran_act = TRUE;
1711                 break;
1712         default:
1713                 warn("unsupported AcT");
1714         }
1715
1716         /* AT-Command */
1717         at_cmd = g_strdup_printf("AT+CPOL=%d,%d,\"%s\",%d,%d,%d",
1718                         pref_plmn->index, 2, pref_plmn->plmn, gsm_act, gsm_compact_act, utran_act);
1719
1720         /* Response callback data */
1721         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1722
1723         /* Send Request to modem */
1724         ret = tcore_at_prepare_and_send_request(co,
1725                 at_cmd, NULL,
1726                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1727                 NULL,
1728                 on_response_imc_network_default, resp_cb_data,
1729                 on_send_imc_request, NULL);
1730         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set preferred plmn");
1731
1732         g_free(at_cmd);
1733         return ret;
1734 }
1735
1736 /*
1737  * Operation -  get preferred plmn
1738  * Request -
1739  * AT-Command: AT+CPOL?
1740  * Response -
1741  * Success: (multiline)
1742  * +CPOL: <index1>,<format>,<oper1>
1743  * [,<GSM_AcT1>,<GSM_Compact_AcT1>,<UTRAN_AcT1>][<CR><LF>
1744  * +CPOL: <index2>,<format>,<oper2>[,<GSM_AcT2>,<GSM_Compact_AcT2>,<UTRAN_AcT2>] [\85]]
1745  *  OK
1746  * Failure
1747  * +CME ERROR: <err>
1748  */
1749 static TelReturn imc_network_get_preferred_plmn(CoreObject *co,
1750         TcoreObjectResponseCallback cb, void *cb_data)
1751 {
1752         ImcRespCbData *resp_cb_data;
1753         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1754         dbg("entry");
1755
1756         /* Response callback data */
1757         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1758
1759         /* Send Request to modem */
1760         ret = tcore_at_prepare_and_send_request(co,
1761                 "AT+CPOL=,2;+CPOL?", "+CPOL", //to make sure <oper> is numeric type in reponse.
1762                 TCORE_AT_COMMAND_TYPE_MULTILINE,
1763                 NULL,
1764                 on_response_imc_network_get_preferred_plmn, resp_cb_data,
1765                 on_send_imc_request, NULL);
1766         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get preferred plmn");
1767
1768         return ret;
1769 }
1770
1771 /*
1772  * Operation -  set network mode
1773  * Request -
1774  * AT-Command: AT+XRAT=<AcT> [, <PreferredAct>]
1775  * where
1776  * <AcT> indicates the radio access technology and may be
1777  * 0 GSM single mode
1778  * 1 GSM / UMTS Dual mode
1779  * 2 UTRAN (UMTS)
1780  * 3-7 Reserved for future use.
1781  * 8 This option is to swap the RAT mode between the two stacks. Example: If Stack1 is in GSM mode and
1782  * Stack2 is in UMTS mode, this will configure Stack1 in UMTS mode and Stack2 in GSM mode.
1783  * Note : <Act> = 8 is used only for dual sim configuration. In this case < PreferredAct > is ignored
1784  * <PreferredAct>
1785  * This parameter is used for network registration in case of <AcT>=1.
1786  * 0 RAT GSM
1787  * 2 RAT UMTS
1788  * Response -
1789  * Success: (No result)
1790  * OK
1791  * Failure:
1792  * +CME ERROR: <error>
1793  */
1794 static TelReturn imc_network_set_mode(CoreObject *co, TelNetworkMode mode,
1795         TcoreObjectResponseCallback cb, void *cb_data)
1796 {
1797         ImcRespCbData *resp_cb_data;
1798         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1799         int act;
1800         gchar *at_cmd;
1801
1802         switch(mode) {
1803         case TEL_NETWORK_MODE_AUTO:
1804                 act = 1;
1805                 break;
1806         case TEL_NETWORK_MODE_2G:
1807                 act = 0;
1808                 break;
1809         case TEL_NETWORK_MODE_3G:
1810                 act = 2;
1811                 break;
1812         case TEL_NETWORK_MODE_LTE:
1813         default:
1814                 err("Unsupported  mode");
1815                 return ret;
1816         }
1817
1818         if (act == 1)
1819                 /* AT-Command */
1820                 at_cmd = g_strdup_printf("AT+XRAT=%d,2", act); //PreferredAct is UMTS
1821         else
1822                 /* AT-Command */
1823                 at_cmd = g_strdup_printf("AT+XRAT=%d", act);
1824
1825         /* Response callback data */
1826         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1827
1828         /* Send Request to modem */
1829         ret = tcore_at_prepare_and_send_request(co,
1830                 at_cmd, NULL ,
1831                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1832                 NULL,
1833                 on_response_imc_network_default, resp_cb_data,
1834                 on_send_imc_request, NULL);
1835         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set network mode");
1836
1837         g_free(at_cmd);
1838         return ret;
1839 }
1840
1841 /*
1842  * Operation -  get network mode
1843  * Request -
1844  * AT-Command: AT+XRAT?
1845  *
1846  * Response -
1847  * Success: (Single line)
1848  * +XRAT : <Act>,<PreferredAct>
1849  * <AcT> indicates the radio access technology and may be
1850  * 0 GSM single mode
1851  * 1 GSM / UMTS Dual mode
1852  * 2 UTRAN (UMTS)
1853  * 3-7 Reserved for future use.
1854  * 8 This option is to swap the RAT mode between the two stacks. Example: If Stack1 is in GSM mode and
1855  * Stack2 is in UMTS mode, this will configure Stack1 in UMTS mode and Stack2 in GSM mode.
1856  * Note : <Act> = 8 is used only for dual sim configuration. In this case < PreferredAct > is ignored
1857  * <PreferredAct>
1858  * This parameter is used for network registration in case of <AcT>=1.
1859  * 0 RAT GSM
1860  * 2 RAT UMTS
1861  * OK
1862  * Failure:
1863  * +CME ERROR: <error>
1864  */
1865
1866 static TelReturn imc_network_get_mode(CoreObject *co,
1867         TcoreObjectResponseCallback cb, void *cb_data)
1868 {
1869         ImcRespCbData *resp_cb_data;
1870         TelReturn ret;
1871         dbg("entry");
1872
1873         /* Response callback data */
1874         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1875
1876         /* Send Request to modem */
1877         ret = tcore_at_prepare_and_send_request(co,
1878                 "AT+XRAT?", "+XRAT",
1879                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1880                 NULL,
1881                 on_response_imc_network_get_mode, resp_cb_data,
1882                 on_send_imc_request, NULL);
1883         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get network mode");
1884
1885         return ret;
1886 }
1887
1888 static TelReturn imc_network_get_neighboring_cell_info(CoreObject *co,
1889         TcoreObjectResponseCallback cb, void *cb_data)
1890 {
1891         /* TODO*/
1892         dbg("entry");
1893         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1894 }
1895
1896 /* Network Operations */
1897 static TcoreNetworkOps imc_network_ops = {
1898         .get_identity_info = imc_network_get_identity_info,
1899         .search = imc_network_search,
1900         .cancel_search = imc_network_cancel_search,
1901         .select_automatic = imc_network_select_automatic,
1902         .select_manual = imc_network_select_manual,
1903         .get_selection_mode = imc_network_get_selection_mode,
1904         .set_preferred_plmn = imc_network_set_preferred_plmn,
1905         .get_preferred_plmn = imc_network_get_preferred_plmn,
1906         .set_mode = imc_network_set_mode,
1907         .get_mode = imc_network_get_mode,
1908         .get_neighboring_cell_info = imc_network_get_neighboring_cell_info
1909 };
1910
1911 gboolean imc_network_init(TcorePlugin *p, CoreObject *co)
1912 {
1913         CustomData *custom_data;
1914         dbg("Enter");
1915
1916         /* Set operations */
1917         tcore_network_set_ops(co, &imc_network_ops);
1918
1919         /* Custom data */
1920         custom_data = tcore_malloc0(sizeof(CustomData));
1921         custom_data->search_state = IMC_NETWORK_SEARCH_STATE_NO_SEARCH;
1922
1923         /* Link Custom data */
1924         tcore_object_link_user_data(co, custom_data);
1925
1926         /* Add Callbacks */
1927         tcore_object_add_callback(co, "+CREG", on_notification_imc_cs_network_info, NULL);
1928         tcore_object_add_callback(co, "+CGREG", on_notification_imc_ps_network_info, NULL);
1929         tcore_object_add_callback(co, "+XNITZINFO", on_notification_imc_network_time_info, NULL);
1930         tcore_object_add_callback(co, "+XCIEV", on_notification_imc_network_rssi, NULL);
1931
1932         /*
1933          * Add Hooks - Request and Notification
1934          */
1935         tcore_plugin_add_request_hook(p,
1936                 TCORE_COMMAND_MODEM_SET_FLIGHTMODE,
1937                 on_hook_imc_set_flight_mode, NULL);
1938         tcore_plugin_add_notification_hook(p,
1939                 TCORE_NOTIFICATION_SIM_STATUS,
1940                 on_hook_imc_sim_status, co);
1941
1942         //_insert_mcc_mnc_oper_list(cp, co_network);
1943
1944         dbg("Exit");
1945         return TRUE;
1946 }
1947
1948 void imc_network_exit(TcorePlugin *p, CoreObject *co)
1949 {
1950         CustomData *custom_data;
1951
1952         custom_data = tcore_object_ref_user_data(co);
1953         if (custom_data != NULL)
1954                 tcore_free(custom_data);
1955
1956         dbg("Exit");
1957 }