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