Fix telephony crash when SIM has invalid message
[platform/core/telephony/tel-plugin-imc.git] / src / s_network.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Harish Bishnoi <hbishnoi@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <glib.h>
26
27 #include <tcore.h>
28 #include <hal.h>
29 #include <core_object.h>
30 #include <plugin.h>
31 #include <user_request.h>
32 #include <queue.h>
33 #include <co_network.h>
34 #include <co_ps.h>
35 #include <server.h>
36 #include <storage.h>
37 #include <util.h>
38 #include <at.h>
39
40 #include "s_common.h"
41 #include "s_network.h"
42
43 #define AT_CREG_STAT_NOT_REG    0 /* not registered, MT is not currently searching a new operator to register to */
44 #define AT_CREG_STAT_REG_HOME   1 /* registered, home network */
45 #define AT_CREG_STAT_SEARCHING  2 /* not registered, but MT is currently searching a new operator to register to */
46 #define AT_CREG_STAT_REG_DENIED 3 /* registration denied */
47 #define AT_CREG_STAT_UNKNOWN    4 /* unknown */
48 #define AT_CREG_STAT_REG_ROAM   5 /* registered, roaming */
49
50 #define AT_COPS_MODE_AUTOMATIC  0 /* automatic (<oper> field is ignored) */
51 #define AT_COPS_MODE_MANUAL 1 /* manual (<oper> field shall be present, and <AcT> optionally) */
52 #define AT_COPS_MODE_DEREGISTER 2 /* deregister from network */
53 #define AT_COPS_MODE_SET_ONLY   3 /* set only <format> */
54 #define AT_COPS_MODE_MANUAL_AUTOMATIC 4 /*automatic - manual*/
55
56 #define AT_COPS_FORMAT_LONG_ALPHANUMERIC    0 /* long format alphanumeric <oper> */
57 #define AT_COPS_FORMAT_SHORT_ALPHANUMERIC   1 /* short format alphanumeric <oper> */
58 #define AT_COPS_FORMAT_NUMERIC          2 /* numeric <oper> */
59
60 #define AT_COPS_ACT_GSM         0   /* GSM */
61 #define AT_COPS_ACT_GSM_COMPACT     1   /* GSM Compact */
62 #define AT_COPS_ACT_UTRAN       2   /* UTRAN */
63 #define AT_COPS_ACT_GSM_EGPRS       3   /* GSM w/EGPRS */
64 #define AT_COPS_ACT_UTRAN_HSDPA     4   /* UTRAN w/HSDPA */
65 #define AT_COPS_ACT_UTRAN_HSUPA     5   /* UTRAN w/HSUPA */
66 #define AT_COPS_ACT_UTRAN_HSDPA_HSUPA   6   /* UTRAN w/HSDPA and HSUPA */
67 #define AT_COPS_ACT_E_UTRAN     7   /* E-UTRAN */
68
69 #define AT_GSM_XBANDSEL_AUTOMATIC 0
70 #define AT_GSM_XBANDSEL_1800 1800
71 #define AT_GSM_XBANDSEL_1900 1900
72 #define AT_GSM_XBANDSEL_900 900
73 #define AT_GSM_XBANDSEL_850 850
74 #define AT_GSM_XBANDSEL_450 450
75 #define AT_GSM_XBANDSEL_480 480
76 #define AT_GSM_XBANDSEL_750 750
77 #define AT_GSM_XBANDSEL_380 380
78 #define AT_GSM_XBANDSEL_410 410
79
80 #define AT_XRAT_GSM 0
81 #define AT_XRAT_DUAL 1
82 #define AT_XRAT_UMTS 2
83
84 #define MAX_NETWORKS_PREF_PLMN_SUPPORT 150
85 #define MAX_NETWORKS_MANUAL_SEARCH_SUPPORT 20
86
87 static unsigned int lookup_tbl_net_status[] = {
88         [AT_CREG_STAT_NOT_REG] = NETWORK_SERVICE_DOMAIN_STATUS_NO,
89         [AT_CREG_STAT_REG_HOME] = NETWORK_SERVICE_DOMAIN_STATUS_FULL,
90         [AT_CREG_STAT_SEARCHING] = NETWORK_SERVICE_DOMAIN_STATUS_SEARCH,
91         [AT_CREG_STAT_REG_DENIED] = NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY,
92         [AT_CREG_STAT_UNKNOWN] = NETWORK_SERVICE_DOMAIN_STATUS_NO,
93         [AT_CREG_STAT_REG_ROAM] = NETWORK_SERVICE_DOMAIN_STATUS_FULL,
94 };
95
96 static unsigned int lookup_tbl_access_technology[] = {
97         [AT_COPS_ACT_GSM] = NETWORK_ACT_GSM,
98         [AT_COPS_ACT_GSM_COMPACT] = NETWORK_ACT_GSM,
99         [AT_COPS_ACT_UTRAN] = NETWORK_ACT_UTRAN,
100         [AT_COPS_ACT_GSM_EGPRS] = NETWORK_ACT_EGPRS,
101         [AT_COPS_ACT_UTRAN_HSDPA] = NETWORK_ACT_UTRAN,
102         [AT_COPS_ACT_UTRAN_HSUPA] = NETWORK_ACT_UTRAN,
103         [AT_COPS_ACT_UTRAN_HSDPA_HSUPA] = NETWORK_ACT_UTRAN,
104         [AT_COPS_ACT_E_UTRAN] = NETWORK_ACT_GSM_UTRAN,
105 };
106
107 static gboolean get_serving_network(CoreObject *o, UserRequest *ur);
108
109
110 static void on_confirmation_network_message_send(TcorePending *p, gboolean result, void *user_data)
111 {
112         dbg("on_confirmation_modem_message_send - msg out from queue.\n");
113
114         if (result == FALSE) {
115                 /* Fail */
116                 dbg("SEND FAIL");
117         } else {
118                 dbg("SEND OK");
119         }
120 }
121
122 static void nwk_prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, UserRequest *ur, TcorePendingResponseCallback callback)
123 {
124         TcoreATRequest *req = NULL;
125         TcoreHal *hal;
126         TcorePending *pending = NULL;
127         TReturn ret;
128
129         hal = tcore_object_get_hal(co);
130
131         pending = tcore_pending_new(co, 0);
132         req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
133
134         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
135
136         tcore_pending_set_request_data(pending, 0, req);
137         tcore_pending_set_response_callback(pending, callback, req->cmd);
138         tcore_pending_link_user_request(pending, ur);
139         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
140
141         ret = tcore_hal_send_request(hal, pending);
142         return;
143 }
144
145
146 static void _insert_mcc_mnc_oper_list(TcorePlugin *p, CoreObject *o)
147 {
148         Server *s;
149         Storage *strg;
150         void *handle;
151         char query[255] = { 0, };
152         GHashTableIter iter;
153         gpointer key, value;
154         GHashTable *result = NULL, *row = NULL;
155         struct tcore_network_operator_info *noi = NULL;
156         int count = 0;
157
158         s = tcore_plugin_ref_server(p);
159         strg = tcore_server_find_storage(s, "database");
160
161         handle = tcore_storage_create_handle(strg, "/opt/dbspace/.mcc_mnc_oper_list.db");
162         if (!handle) {
163                 dbg("fail to create database handle");
164                 return;
165         }
166
167         snprintf(query, 255, "select country, mcc, mnc, oper from mcc_mnc_oper_list");
168
169         result = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
170                                                                    (GDestroyNotify) g_hash_table_destroy);
171
172         tcore_storage_read_query_database(strg, handle, query, NULL, result, 4);
173
174         g_hash_table_iter_init(&iter, result);
175         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
176                 row = value;
177
178                 noi = calloc(sizeof(struct tcore_network_operator_info), 1);
179
180                 snprintf(noi->mcc, 4, "%s", (char *) g_hash_table_lookup(row, "1"));
181                 snprintf(noi->mnc, 4, "%s", (char *) g_hash_table_lookup(row, "2"));
182                 snprintf(noi->name, 41, "%s", (char *) g_hash_table_lookup(row, "3"));
183                 snprintf(noi->country, 4, "%s", (char *) g_hash_table_lookup(row, "0"));
184
185                 tcore_network_operator_info_add(o, noi);
186
187                 count++;
188         }
189
190         dbg("count = %d", count);
191
192         g_hash_table_destroy(result);
193
194         tcore_storage_remove_handle(strg, handle);
195 }
196
197 static enum telephony_network_service_type _get_service_type(enum telephony_network_service_type prev_type,
198                                                                                                                          int domain, int act, int cs_status, int ps_status)
199 {
200         enum telephony_network_service_type ret;
201
202         ret = prev_type;
203
204         switch (act) {
205         case NETWORK_ACT_UNKNOWN:
206                 ret = NETWORK_SERVICE_TYPE_UNKNOWN;
207                 break;
208
209         case NETWORK_ACT_GSM:
210                 if (prev_type == NETWORK_SERVICE_TYPE_2_5G_EDGE && domain == NETWORK_SERVICE_DOMAIN_CS)
211                         ret = NETWORK_SERVICE_TYPE_2_5G_EDGE;
212                 else
213                         ret = NETWORK_SERVICE_TYPE_2G;
214                 break;
215
216         case NETWORK_ACT_EGPRS:
217                 return NETWORK_SERVICE_TYPE_2_5G_EDGE;
218                 break;
219
220         case NETWORK_ACT_UMTS:
221                 ret = NETWORK_SERVICE_TYPE_3G;
222                 break;
223         }
224
225         if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_NO && ps_status == NETWORK_SERVICE_DOMAIN_STATUS_NO) {
226                 ret = NETWORK_SERVICE_TYPE_NO_SERVICE;
227         } else if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_SEARCH || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_SEARCH) {
228                 if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
229                         /* no change */
230                 } else {
231                         ret = NETWORK_SERVICE_TYPE_SEARCH;
232                 }
233         } else if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY) {
234                 if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
235                         /* no change */
236                 } else {
237                         ret = NETWORK_SERVICE_TYPE_EMERGENCY;
238                 }
239         }
240
241         return ret;
242 }
243
244 static void _ps_set(TcorePlugin *p, int status)
245 {
246         CoreObject *co_ps;
247
248         co_ps = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_PS);
249         if (co_ps == NULL) {
250                 err("No PS Core Object on plugin");
251                 return;
252         }
253
254         if (status == NETWORK_SERVICE_DOMAIN_STATUS_FULL)
255                 tcore_ps_set_online(co_ps, TRUE);
256         else
257                 tcore_ps_set_online(co_ps, FALSE);
258 }
259
260 static void on_timeout_search_network(TcorePending *p, void *user_data)
261 {
262         UserRequest *ur;
263         struct tresp_network_search resp;
264
265         dbg("TIMEOUT !!!!! pending=%p", p);
266
267         memset(&resp, 0, sizeof(struct tresp_network_search));
268
269         resp.result = TCORE_RETURN_FAILURE;
270         resp.list_count = 0;
271
272         ur = tcore_pending_ref_user_request(p);
273         if (ur) {
274                 tcore_user_request_send_response(ur, TRESP_NETWORK_SEARCH, sizeof(struct tresp_network_search), &resp);
275         }
276 }
277
278 static void on_response_set_plmn_selection_mode(TcorePending *p, int data_len, const void *data, void *user_data)
279 {
280         UserRequest *ur;
281         const TcoreATResponse *atResp = data;
282         // GSList *tokens = NULL;
283         // char * line = NULL;
284         struct tresp_network_set_plmn_selection_mode resp = {0};
285
286         if (atResp->success > 0) {
287                 dbg("RESPONSE OK");
288                 resp.result = TCORE_RETURN_SUCCESS;
289         } else {
290                 dbg("RESPONSE NOK");
291                 resp.result = TCORE_RETURN_FAILURE;
292         }
293
294         ur = tcore_pending_ref_user_request(p);
295         if (ur) {
296                 tcore_user_request_send_response(ur, TRESP_NETWORK_SET_PLMN_SELECTION_MODE, sizeof(struct tresp_network_set_plmn_selection_mode), &resp);
297         }
298 }
299
300 static void on_response_get_plmn_selection_mode(TcorePending *p, int data_len, const void *data, void *user_data)
301 {
302         UserRequest *ur;
303         struct tresp_network_get_plmn_selection_mode resp = {0};
304         const TcoreATResponse *atResp = data;
305         GSList *tokens = NULL;
306         char *line = NULL;
307         int mode = 0;
308
309         resp.result = TCORE_RETURN_FAILURE;
310
311         if (atResp->success > 0) {
312                 dbg("RESPONSE OK");
313                 /* Format of output
314                 +COPS: <mode>[,<format>,<oper>[,< AcT>]]
315                 */
316
317                 if (atResp->lines) {
318                         line = (char *) atResp->lines->data;
319                         tokens = tcore_at_tok_new(line);
320                         if (g_slist_length(tokens) < 1) {
321                                 msg("invalid message");
322                                 goto OUT;
323                         }
324                         mode = atoi(tcore_at_tok_nth(tokens, 0));
325                         dbg("mode = %d", mode);
326
327                         switch (mode) {
328                         case AT_COPS_MODE_AUTOMATIC:
329                                 resp.mode = NETWORK_SELECT_MODE_AUTOMATIC;
330                                 break;
331
332                         case AT_COPS_MODE_MANUAL:
333                         case AT_COPS_MODE_MANUAL_AUTOMATIC:
334                                 resp.mode = NETWORK_SELECT_MODE_MANUAL;
335                                 break;
336
337                         case AT_COPS_MODE_DEREGISTER:
338                         case AT_COPS_MODE_SET_ONLY:
339                                 resp.result = TCORE_RETURN_FAILURE;
340                                 goto OUT;
341                         }
342                         resp.result = TCORE_RETURN_SUCCESS;
343                 }
344         } else {
345                 dbg("RESPONSE NOK");
346                 resp.result = TCORE_RETURN_FAILURE;
347         }
348
349 OUT:
350         ur = tcore_pending_ref_user_request(p);
351         if (ur) {
352                 tcore_user_request_send_response(ur, TRESP_NETWORK_GET_PLMN_SELECTION_MODE, sizeof(struct tresp_network_get_plmn_selection_mode), &resp);
353         }
354
355         if (tokens != NULL)
356                 tcore_at_tok_free(tokens);
357
358         return;
359 }
360
361 static void on_response_search_network(TcorePending *p, int data_len, const void *data, void *user_data)
362 {
363         UserRequest *ur;
364         struct tresp_network_search resp;
365         int i = 0;
366         char *line = NULL;
367         const TcoreATResponse *atResp = data;
368         GSList *tokens = NULL;
369         GSList *network_token = NULL;
370         int AcT = 0;
371         char *temp_plmn_info = NULL;
372         char *alpha_name = NULL;
373         char *pResp = NULL;
374         int num_network_avail = 0;
375
376         memset(&resp, 0, sizeof(struct tresp_network_search));
377         resp.result = TCORE_RETURN_FAILURE;
378         resp.list_count = 0;
379
380         if (atResp->success > 0) {
381                 dbg("RESPONSE OK");
382                 if (atResp->lines) {
383                         line = (char *) atResp->lines->data;
384                         tokens = tcore_at_tok_new(line);
385                         num_network_avail = g_slist_length(tokens);
386                         dbg(" length of tokens is %d\n", num_network_avail);
387                         if (num_network_avail < 1) {
388                                 msg("invalid message");
389                                 goto OUT;
390                         }
391                 }
392
393                 resp.result = TCORE_RETURN_SUCCESS;
394                 /*
395                  *      +COPS: [list of supported (<stat>,long alphanumeric <oper>,short alphanumeric <oper>,numeric <oper>[,<AcT>])s]
396                  *             [,,(list of supported <mode>s),(list of supported <format>s)]
397                 */
398
399                 for (i = 0; ((i < num_network_avail) && (i < MAX_NETWORKS_MANUAL_SEARCH_SUPPORT)); i++) {
400                         network_token = tcore_at_tok_new(g_slist_nth_data(tokens, i));
401
402                         pResp = (tcore_at_tok_nth(network_token, 0));
403                         if (pResp != NULL) {
404                                 dbg("status : %s", pResp);
405                                 resp.list[i].status = (enum telephony_network_plmn_status) atoi(pResp);
406                         }
407
408                         if ((pResp = tcore_at_tok_nth(network_token, 1))) {     /* Long Alpha name */
409                                 dbg("Long Alpha name : %s", pResp);
410
411                                 if (strlen(pResp) > 0)
412                                         /* Strip off starting quote & ending quote */
413                                         strncpy(resp.list[i].name, pResp + 1, strlen(pResp) - 2);
414                         }
415
416                         if ((pResp = tcore_at_tok_nth(network_token, 2))) {
417                                 dbg("Short Aplha name : %s", pResp);
418                                 /* Short Aplha name */
419                                 /* Strip off starting quote & ending quote */
420                                 if (strlen(pResp) > 0)
421                                         strncpy(resp.list[i].name, pResp + 1, strlen(pResp) - 2);
422                         }
423
424                         /* PLMN ID */
425                         pResp = tcore_at_tok_nth(network_token, 3);
426                         if (pResp != NULL) {
427                                 dbg("PLMN ID : %s", pResp);
428                                 temp_plmn_info = tcore_at_tok_extract((const char *)pResp);
429                                 strncpy(resp.list[i].plmn, temp_plmn_info, 6);
430                                 resp.list[i].plmn[6] = '\0';
431                         }
432
433                         /* Parse Access Technology */
434                         if ((pResp = tcore_at_tok_nth(network_token, 4))) {
435                                 if (strlen(pResp) > 0) {
436                                         AcT = atoi(pResp);
437
438                                         if (0 == AcT)
439                                                 resp.list[i].act = NETWORK_ACT_GSM;
440                                         else if (2 == AcT)
441                                                 resp.list[i].act = NETWORK_ACT_UMTS;
442                                 }
443                         }
444
445                         dbg("Operator [%d] :: stat = %d, Name =%s, plmnId = %s, AcT=%d\n", resp.list_count, resp.list[i].status, resp.list[i].name, resp.list[i].plmn, resp.list[i].act);
446                         resp.list_count++;
447
448                         tcore_at_tok_free(network_token);
449                         g_free(alpha_name);
450                         g_free(temp_plmn_info);
451                 }
452         } else {
453                 dbg("RESPONSE NOK");
454                 resp.result = TCORE_RETURN_FAILURE;
455         }
456
457 OUT:
458         ur = tcore_pending_ref_user_request(p);
459         if (ur) {
460                 tcore_user_request_send_response(ur, TRESP_NETWORK_SEARCH, sizeof(struct tresp_network_search), &resp);
461         }
462
463         /* Free tokens */
464         tcore_at_tok_free(tokens);
465 }
466
467 static void on_response_set_umts_band(TcorePending *p, int data_len, const void *data, void *user_data)
468 {
469         const TcoreATResponse *atResp = data;
470
471         dbg("On Response Set UMTS Band");
472
473         if (atResp->success > 0) {
474                 dbg("Response OK");
475         } else {
476                 dbg("Response NOK");
477         }
478
479         dbg("Wait for response of XRAT before sending final band setting response to AP");
480         return;
481 }
482
483
484 static void on_response_set_gsm_band(TcorePending *p, int data_len, const void *data, void *user_data)
485 {
486         const TcoreATResponse *atResp = data;
487
488         dbg("On Response Set GSM Band");
489         if (atResp->success > 0) {
490                 dbg("Response OK");
491         } else {
492                 dbg("Response NOK");
493         }
494
495         dbg("Wait for response of XRAT before sending final band setting response to AP");
496         return;
497 }
498
499 static void on_response_get_umts_band(TcorePending *p, int data_len, const void *data, void *user_data)
500 {
501         const TcoreATResponse *atResp = data;
502         GSList *tokens = NULL;
503         const char *line = NULL;
504         int total_umts_bands = 0;
505         int i = 0;
506         char *band_token = NULL;
507         char umts_band[20] = {0};
508         char umts_band_1 = 0;
509         char umts_band_2 = 0;
510         char umts_band_5 = 0;
511         UserRequest *ur = NULL;
512         struct tresp_network_get_band resp = {0};
513
514         dbg("Entry on_response_get_umts_band");
515
516         resp.mode = NETWORK_BAND_MODE_PREFERRED;
517         resp.result = TCORE_RETURN_SUCCESS;
518
519         if (atResp->success > 0) {
520                 dbg("RESPONSE OK");
521                 if (atResp->lines) {
522                         line = (char *) atResp->lines->data;
523                         tokens = tcore_at_tok_new(line);
524                         total_umts_bands = g_slist_length(tokens);
525                         dbg("Total UMTS bands enabled are : %d\n", total_umts_bands);
526                         if (total_umts_bands < 1) {
527                                 goto OUT;
528                         }
529                 }
530         } else {
531                 dbg("RESPONSE NOK");
532                 goto OUT;
533         }
534
535         for (i = 0; i < total_umts_bands; i++) {
536                 band_token = tcore_at_tok_nth(tokens, i);
537
538                 if (band_token == NULL)
539                         continue;
540
541                 memset(umts_band, 0x00, sizeof(umts_band));
542
543                 if (atoi(band_token) == 0) { /* 0 means UMTS automatic */
544                         umts_band_1 = umts_band_2 = umts_band_5 = TRUE;
545                         break;
546                 }
547
548                 /* Strip off starting quotes & ending quotes */
549                 strncpy(umts_band, band_token + 1, strlen(band_token) - 2);
550
551                 if (!strcmp(umts_band, "UMTS_BAND_I")) {
552                         umts_band_1 = TRUE;
553                 } else if (!strcmp(umts_band, "UMTS_BAND_II")) {
554                         umts_band_2 = TRUE;
555                 } else if (!strcmp(umts_band, "UMTS_BAND_II")) {
556                         umts_band_5 = TRUE;
557                 } else {
558                         /* Telephony is not interest */
559                         dbg("Telephony is not interested in %s band", umts_band);
560                 }
561         }
562
563 OUT:
564         if ((umts_band_1) && (umts_band_2) && (umts_band_5)) {
565                 resp.band = NETWORK_BAND_TYPE_WCDMA;
566         } else if (umts_band_1) {
567                 resp.band = NETWORK_BAND_TYPE_WCDMA2100;
568         } else if (umts_band_2) {
569                 resp.band = NETWORK_BAND_TYPE_WCDMA1900;
570         } else if (umts_band_5) {
571                 resp.band = NETWORK_BAND_TYPE_WCDMA850;
572         } else {
573                 resp.result = TCORE_RETURN_FAILURE;
574         }
575
576         dbg("Final resp.band sent to TS = %d", resp.band);
577
578         ur = tcore_pending_ref_user_request(p);
579         if (ur) {
580                 tcore_user_request_send_response(ur, TRESP_NETWORK_GET_BAND, sizeof(struct tresp_network_get_band), &resp);
581         }
582
583         if (tokens != NULL)
584                 tcore_at_tok_free(tokens);
585
586         dbg("Exit on_response_get_umts_band");
587         return;
588 }
589
590 static void on_response_get_gsm_band(TcorePending *p, int data_len, const void *data, void *user_data)
591 {
592         struct tresp_network_get_band resp = {0};
593         const TcoreATResponse *atResp = data;
594         GSList *tokens = NULL;
595         int total_gsm_bands = 0;
596         const char *line = NULL;
597         int i = 0;
598         char *band_token = NULL;
599         UserRequest *ur = NULL;
600         int gsm_850 = 0;
601         int gsm_900 = 0;
602         int gsm_1800 = 0;
603         int gsm_1900 = 0;
604
605         dbg("Entry on_response_get_gsm_band");
606
607         resp.mode = NETWORK_BAND_MODE_PREFERRED;
608         resp.result = TCORE_RETURN_SUCCESS;
609
610         if (atResp->success > 0) {
611                 dbg("RESPONSE OK");
612                 if (atResp->lines) {
613                         line = (char *) atResp->lines->data;
614                         tokens = tcore_at_tok_new(line);
615                         total_gsm_bands = g_slist_length(tokens);
616                         dbg("Total GSM bands enabled are : %d\n", total_gsm_bands);
617                         if (total_gsm_bands < 1)
618                                 goto OUT;
619                 }
620         }
621
622         for (i = 0; i < total_gsm_bands; i++) {
623                 band_token = tcore_at_tok_nth(tokens, i);
624
625                 if (band_token == NULL)
626                         continue;
627
628                 if (atoi(band_token) == 0) { /* 0 means GSM automatic */
629                         gsm_850 = gsm_900 = gsm_1800 = gsm_1900 = TRUE;
630                         break;
631                 }
632
633                 switch (atoi(band_token)) {
634                 case AT_GSM_XBANDSEL_850:
635                         gsm_850 = TRUE;
636                         break;
637
638                 case AT_GSM_XBANDSEL_900:
639                         gsm_900 = TRUE;
640                         break;
641
642                 case AT_GSM_XBANDSEL_1800:
643                         gsm_1800 = TRUE;
644                         break;
645
646                 case AT_GSM_XBANDSEL_1900:
647                         gsm_1900 = TRUE;
648                         break;
649
650                 default:
651                         break;
652                 }
653         }
654
655 OUT:
656
657         if (gsm_850 && gsm_900 && gsm_1800 && gsm_1900) {
658                 resp.band = NETWORK_BAND_TYPE_GSM;
659         } else if (gsm_850 && gsm_1900) {
660                 resp.band = NETWORK_BAND_TYPE_GSM_850_1900;
661         } else if (gsm_900 && gsm_1800) {
662                 resp.band = NETWORK_BAND_TYPE_GSM_900_1800;
663         } else if (gsm_1900) {
664                 resp.band = NETWORK_BAND_TYPE_GSM1900;
665         } else if (gsm_850) {
666                 resp.band = NETWORK_BAND_TYPE_GSM850;
667         } else if (gsm_1800) {
668                 resp.band = NETWORK_BAND_TYPE_GSM1800;
669         } else if (gsm_900) {
670                 resp.band = NETWORK_BAND_TYPE_GSM900;
671         } else {
672                 resp.result = TCORE_RETURN_FAILURE;
673         }
674
675         dbg("Final resp.band sent to TS = %d", resp.band);
676
677         ur = tcore_pending_ref_user_request(p);
678         if (ur) {
679                 tcore_user_request_send_response(ur, TRESP_NETWORK_GET_BAND, sizeof(struct tresp_network_get_band), &resp);
680         }
681
682         if (tokens != NULL)
683                 tcore_at_tok_free(tokens);
684
685         dbg("Exit on_response_get_gsm_band");
686         return;
687 }
688
689
690 static void on_response_get_xrat(TcorePending *p, int data_len, const void *data, void *user_data)
691 {
692         TcoreHal *h = NULL;
693         UserRequest *ur = NULL;
694
695         TcoreATRequest *atreq;
696         char *cmd_str = NULL;
697         UserRequest *dup_ur = NULL;
698         const TcoreATResponse *atResp = data;
699         const char *line = NULL;
700         char *pResp = NULL;
701         GSList *tokens = NULL;
702         TcorePending *pending = NULL;
703         CoreObject *o = NULL;
704         int cp_xrat = 0;
705         struct tresp_network_get_band resp = {0};
706
707         dbg("Enter on_response_get_xrat !!");
708
709         resp.mode = NETWORK_BAND_MODE_PREFERRED;
710
711         ur = tcore_pending_ref_user_request(p);
712         h = tcore_object_get_hal(tcore_pending_ref_core_object(p));
713         o = tcore_pending_ref_core_object(p);
714
715         if (atResp->success > 0) {
716                 dbg("RESPONSE OK");
717                 if (atResp->lines) {
718                         line = (char *) atResp->lines->data;
719                         tokens = tcore_at_tok_new(line);
720                         if (g_slist_length(tokens) < 1) {
721                                 msg("invalid message");
722                                 goto OUT;
723                         }
724                 }
725
726                 if ((pResp = tcore_at_tok_nth(tokens, 0))) {
727                         cp_xrat = atoi(pResp);
728
729                         if ((cp_xrat == AT_XRAT_DUAL)) {   /* mode is Dual, send reply to Telephony */
730                                 resp.result = TCORE_RETURN_SUCCESS;
731                                 resp.band = NETWORK_BAND_TYPE_ANY;
732
733                                 ur = tcore_pending_ref_user_request(p);
734                                 if (ur) {
735                                         tcore_user_request_send_response(ur, TRESP_NETWORK_GET_BAND, sizeof(struct tresp_network_get_band), &resp);
736                                 }
737                                 goto OUT;
738                         } else if ((cp_xrat == AT_XRAT_UMTS)) {
739                                 /* Get UMTS Band Information */
740                                 dup_ur = tcore_user_request_ref(ur); /* duplicate user request for AT+XUBANDSEL */
741                                 cmd_str = g_strdup_printf("AT+XUBANDSEL?");
742                                 atreq = tcore_at_request_new(cmd_str, "+XUBANDSEL", TCORE_AT_SINGLELINE);
743                                 pending = tcore_pending_new(o, 0);
744                                 tcore_pending_set_request_data(pending, 0, atreq);
745                                 tcore_pending_set_response_callback(pending, on_response_get_umts_band, NULL);
746                                 tcore_pending_link_user_request(pending, ur);
747                                 tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
748                                 tcore_hal_send_request(h, pending);
749                                 g_free(cmd_str);
750                         } else if ((cp_xrat == AT_XRAT_UMTS)) {
751                                 /* Get GSM Band Information */
752                                 dup_ur = tcore_user_request_ref(ur); /* duplicate user request for AT+XBANDSEL */
753                                 cmd_str = g_strdup_printf("AT+XBANDSEL?");
754                                 atreq = tcore_at_request_new(cmd_str, "+XBANDSEL", TCORE_AT_SINGLELINE);
755                                 pending = tcore_pending_new(o, 0);
756                                 tcore_pending_set_request_data(pending, 0, atreq);
757                                 tcore_pending_set_response_callback(pending, on_response_get_gsm_band, NULL);
758                                 tcore_pending_link_user_request(pending, dup_ur);
759                                 tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
760                                 tcore_hal_send_request(h, pending);
761                                 g_free(cmd_str);
762                         }
763                 }
764         } else {
765                 dbg("RESPONSE NOK");
766
767                 resp.result = TCORE_RETURN_FAILURE;
768                 resp.band = NETWORK_BAND_TYPE_ANY;
769
770                 ur = tcore_pending_ref_user_request(p);
771                 if (ur) {
772                         tcore_user_request_send_response(ur, TRESP_NETWORK_GET_BAND, sizeof(struct tresp_network_get_band), &resp);
773                 }
774         }
775 OUT:
776
777         if (tokens != NULL)
778                 tcore_at_tok_free(tokens);
779
780         dbg("Exit on_response_get_xrat !!");
781
782         return;
783 }
784
785
786 static void on_response_set_xrat(TcorePending *p, int data_len, const void *data, void *user_data)
787 {
788         UserRequest *ur = NULL;
789         struct tresp_network_set_band resp = {0};
790         const TcoreATResponse *atResp = data;
791
792         dbg("On Response Set XRAT");
793
794         if (atResp->success > 0) {
795                 dbg("Response OK");
796                 resp.result = TCORE_RETURN_SUCCESS;
797         } else {
798                 dbg("Response NOK");
799                 resp.result = TCORE_RETURN_FAILURE;
800         }
801
802         ur = tcore_pending_ref_user_request(p);
803         if (ur) {
804                 tcore_user_request_send_response(ur, TRESP_NETWORK_SET_BAND, sizeof(struct tresp_network_set_band), &resp);
805         }
806
807         return;
808 }
809
810 static void on_response_set_preferred_plmn(TcorePending *p, int data_len, const void *data, void *user_data)
811 {
812         UserRequest *ur = NULL;
813         struct tresp_network_set_preferred_plmn resp = {0};
814         const TcoreATResponse *atResp = data;
815
816         dbg("ENTER on_response_set_preferred_plmn");
817
818         if (atResp->success > 0) {
819                 dbg("Response OK");
820                 resp.result = TCORE_RETURN_SUCCESS;
821         } else {
822                 dbg("Response NOK");
823                 resp.result = TCORE_RETURN_FAILURE;
824         }
825
826         ur = tcore_pending_ref_user_request(p);
827         if (ur) {
828                 tcore_user_request_send_response(ur, TRESP_NETWORK_SET_PREFERRED_PLMN, sizeof(struct tresp_network_set_preferred_plmn), &resp);
829         }
830
831         dbg("Exit on_response_set_preferred_plmn");
832         return;
833 }
834
835 static void on_response_get_nitz_name(TcorePending *p, int data_len, const void *data, void *user_data)
836 {
837         const TcoreATResponse *atResp = data;
838         GSList *tokens = NULL;
839         const char *line = NULL;
840         CoreObject *o = NULL;
841         struct tnoti_network_identity noti;
842         int nol = 0;
843         int count = 0;
844         int net_name_type = 0;
845         char *pResp = NULL;
846         char *net_name = NULL;
847
848         dbg("Entry on_response_get_nitz_name (+XCOPS)");
849         o = tcore_pending_ref_core_object(p);
850         if (atResp->success > 0) {
851                 dbg("RESPONSE OK");
852
853                 if (atResp->lines) {
854                         nol = g_slist_length(atResp->lines);
855                         if (nol > 3) {
856                                 msg("invalid message");
857                                 goto OUT;
858                         }
859
860                         memset(&noti, 0, sizeof(struct tnoti_network_identity));
861
862                         for (count = 0; count < nol; count++) {
863                                 // parse each line
864                                 line = g_slist_nth_data(atResp->lines, count);
865                                 tokens = tcore_at_tok_new(line);
866                                 dbg("line %d start---------------", count);
867
868                                 if ((pResp = tcore_at_tok_nth(tokens, 0))) {
869                                         net_name_type = atoi(pResp);
870                                         dbg("Net name type  : %d", net_name_type);
871
872                                         switch (net_name_type) {
873                                         case 0: /* plmn_id (mcc, mnc) */
874                                                 if ((pResp = tcore_at_tok_nth(tokens, 1))) {
875                                                         if (strlen(pResp) > 0) {
876                                                                 net_name = tcore_at_tok_extract((const char *)pResp);
877                                                                 strncpy(noti.plmn, net_name, 6);
878                                                                 noti.plmn[6] = '\0';
879                                                         }
880                                                 }
881                                                 break;
882
883                                         case 5: /* Short NITZ name*/
884                                         case 3: /* Short Network Name (CPHS) */
885                                                 if ((pResp = tcore_at_tok_nth(tokens, 1))) {
886                                                         if (strlen(pResp) > 0) {
887                                                                 net_name = tcore_at_tok_extract((const char *)pResp);
888                                                                 strncpy(noti.short_name, net_name, 16);
889                                                                 noti.short_name[16] = '\0';
890                                                         }
891                                                 }
892                                                 break;
893
894                                         case 6: /* Full NITZ name */
895                                         case 4: /* Long Network Name (CPHS) */
896                                                 if ((pResp = tcore_at_tok_nth(tokens, 1))) {
897                                                         if (strlen(pResp) > 0) {
898                                                                 net_name = tcore_at_tok_extract((const char *)pResp);
899                                                                 strncpy(noti.full_name, net_name, 32);
900                                                                 noti.full_name[32] = '\0';
901                                                         }
902                                                 }
903                                                 break;
904
905                                         default:
906                                                 break;
907                                         }
908
909                                         g_free(net_name);
910                                         net_name = NULL;
911                                 }
912
913                                 tcore_at_tok_free(tokens);
914                         }
915
916                         dbg("plmn <%s> short NITZ name<%s> full NITZ name<%s>",
917                                 noti.plmn, noti.short_name, noti.full_name);
918                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_IDENTITY,
919                                                                                    sizeof(struct tnoti_network_identity), &noti);
920                 }
921         } else {
922                 dbg("RESPONSE NOK");
923         }
924
925 OUT:
926         dbg("Exit on_response_get_nitz_name");
927 }
928
929 static void on_response_get_preferred_plmn(TcorePending *p, int data_len, const void *data, void *user_data)
930 {
931         UserRequest *ur;
932         int i = 0;
933         char *line = NULL;
934         const TcoreATResponse *atResp = data;
935         GSList *tokens = NULL;
936         char *pResp = NULL;
937         int plmn_format = 0;
938
939         struct tresp_network_get_preferred_plmn resp = {0};
940         int total_lines = 0;
941         int GSM_AcT2 = 0, GSM_Compact_AcT2 = 0, UTRAN_AcT2 = 0;
942
943         dbg("Entry");
944
945         if (atResp->success > 0) {
946                 dbg("RESPONSE OK");
947                 if (atResp->lines) {
948                         total_lines = g_slist_length(atResp->lines);
949                         dbg("Total number of network present in Preferred PLMN list is %d\n", total_lines);
950
951                         if (total_lines < 1) {
952                                 msg("invalid message");
953                                 goto OUT;
954                         }
955
956                         if (total_lines >= MAX_NETWORKS_PREF_PLMN_SUPPORT)
957                                 total_lines = MAX_NETWORKS_PREF_PLMN_SUPPORT;
958
959 /*
960 +CPOL: <index1>,<format>,<oper1>[,<GSM_AcT1>,<GSM_Compact_AcT1>,<UTRAN_AcT1>,<E-UTRAN_AcT1>] [<CR><LF>
961 +CPOL: <index2>,<format>,<oper2>[,<GSM_AcT2>,<GSM_Compact_AcT2>,<UTRAN_AcT2>,<E-UTRAN_AcT2>]
962 */
963                         resp.result = TCORE_RETURN_SUCCESS;
964
965                         for (i = 0; i < total_lines; i++) {
966                                 /* Take each line response at a time & parse it */
967                                 line = tcore_at_tok_nth(atResp->lines, i);
968                                 tokens = tcore_at_tok_new(line);
969
970                                 /* <index2>,<format>,<oper2>[,<GSM_AcT2>,<GSM_Compact_AcT2>,<UTRAN_AcT2>,<E-UTRAN_AcT2>] */
971
972                                 /* EF Index */
973                                 if ((pResp = tcore_at_tok_nth(tokens, 0))) {
974                                         dbg("Index : %s", pResp);
975                                         resp.list[i].index = atoi(pResp);
976                                 }
977                                 /* Format */
978                                 if ((pResp = tcore_at_tok_nth(tokens, 1))) {
979                                         dbg("format : %s", pResp);
980                                         plmn_format = atoi(pResp);
981                                 }
982
983                                 /* Operator PLMN ID */
984                                 if ((pResp = tcore_at_tok_nth(tokens, 2))) {
985                                         dbg("plmn ID : %s", pResp);
986
987                                         if (strlen(pResp) > 0) {
988                                                 char *oper;
989
990                                                 oper = tcore_at_tok_extract((const char *)pResp);
991                                                 dbg("operator <%s>", oper);
992
993                                                 // Get only PLMN ID
994                                                 if (plmn_format == 2) {
995                                                         strncpy(resp.list[i].plmn, oper, 6);
996                                                         resp.list[i].plmn[6] = '\0';
997                                                 }
998
999                                                 g_free (oper);
1000                                         }
1001                                 }
1002
1003                                 if ((pResp = tcore_at_tok_nth(tokens, 3))) {
1004                                         dbg("GSM_AcT2  : %s", pResp);
1005                                         GSM_AcT2 = atoi(pResp);
1006                                 }
1007
1008                                 if ((pResp = tcore_at_tok_nth(tokens, 4))) {
1009                                         dbg("GSM_Compact AcT2  : %s", pResp);
1010                                         GSM_Compact_AcT2 = atoi(pResp);
1011                                 }
1012
1013                                 if ((pResp = tcore_at_tok_nth(tokens, 5))) {
1014                                         dbg("UTRAN_AcT2  : %s", pResp);
1015                                         UTRAN_AcT2 = atoi(pResp);
1016                                 }
1017
1018                                 if (UTRAN_AcT2 && (GSM_AcT2 || GSM_Compact_AcT2))
1019                                         resp.list[i].act = NETWORK_ACT_GSM_UTRAN;
1020                                 else if (UTRAN_AcT2)
1021                                         resp.list[i].act = NETWORK_ACT_UMTS;
1022                                 else if (GSM_AcT2 || GSM_Compact_AcT2)
1023                                         resp.list[i].act = NETWORK_ACT_GPRS;
1024
1025                                 (resp.list_count)++;
1026
1027                                 tcore_at_tok_free(tokens);
1028                         }
1029                 }
1030         } else {
1031                 dbg("RESPONSE NOT OK");
1032                 // TODO: CMEE error mapping is required.
1033                 resp.result = TCORE_RETURN_FAILURE;
1034         }
1035
1036 OUT:
1037         ur = tcore_pending_ref_user_request(p);
1038         if (ur) {
1039                 tcore_user_request_send_response(ur, TRESP_NETWORK_GET_PREFERRED_PLMN, sizeof(struct tresp_network_get_preferred_plmn), &resp);
1040         }
1041         dbg("Exit");
1042         return;
1043 }
1044
1045 static void on_response_get_serving_network(TcorePending *p, int data_len, const void *data, void *user_data)
1046 {
1047         const TcoreATResponse *resp = data;
1048         UserRequest *ur;
1049         struct tresp_network_get_serving_network Tresp = {0};
1050         char *long_plmn_name = NULL;
1051         char *short_plmn_name = NULL;
1052         char *plmn_id = NULL;
1053         CoreObject *o;
1054         GSList *tokens = NULL;
1055         const char *line;
1056         int network_mode = -1;
1057         int plmn_format = -1;
1058         int AcT = -1;
1059         struct tnoti_network_identity noti;
1060         char *pResp = NULL;
1061         int nol, count = 0;
1062
1063         o = tcore_pending_ref_core_object(p);
1064
1065         if (resp->success <= 0) {
1066                 dbg("RESPONSE NOK");
1067
1068                 ur = tcore_pending_ref_user_request(p);
1069                 if (ur) {
1070                         Tresp.result = TCORE_RETURN_FAILURE;
1071                         tcore_user_request_send_response(ur, TRESP_NETWORK_GET_SERVING_NETWORK, sizeof(struct tresp_network_get_serving_network), &Tresp);
1072                 }
1073
1074                 return;
1075         } else {
1076                 dbg("RESPONSE OK");
1077                 nol = g_slist_length(resp->lines);
1078                 dbg("nol : %d", nol);
1079
1080                 for (count = 0; count < nol; count++) {
1081                         // parse each line
1082                         line = g_slist_nth_data(resp->lines, count);
1083                         tokens = tcore_at_tok_new(line);
1084                         dbg("line %d start---------------", count);
1085                         // mode
1086                         if ((pResp = tcore_at_tok_nth(tokens, 0))) {
1087                                 dbg("mode  : %s", pResp);
1088                                 network_mode = atoi(pResp);
1089                         }
1090
1091                         // format (optional)
1092                         if ((pResp = tcore_at_tok_nth(tokens, 1))) {
1093                                 dbg("format  : %s", pResp);
1094                                 if (strlen(pResp) > 0)
1095                                         plmn_format = atoi(pResp);
1096                         }
1097
1098                         // plmn
1099                         switch (plmn_format) {
1100                         case AT_COPS_FORMAT_LONG_ALPHANUMERIC:
1101                                 if ((pResp = tcore_at_tok_nth(tokens, 2))) {
1102                                         dbg("long PLMN  : %s", pResp);
1103                                         if (strlen(pResp) > 0) {
1104                                                 long_plmn_name = tcore_at_tok_extract((const char *)pResp);
1105
1106                                                 // set network name into po
1107                                                 tcore_network_set_network_name(o, TCORE_NETWORK_NAME_TYPE_FULL, long_plmn_name);
1108                                         }
1109                                 }
1110                                 break;
1111
1112                         case AT_COPS_FORMAT_SHORT_ALPHANUMERIC:
1113                                 if ((pResp = tcore_at_tok_nth(tokens, 2))) {
1114                                         dbg("short PLMN  : %s", pResp);
1115                                         if (strlen(pResp) > 0) {
1116                                                 short_plmn_name = tcore_at_tok_extract((const char *)pResp);
1117
1118                                                 // set network name into po
1119                                                 tcore_network_set_network_name(o, TCORE_NETWORK_NAME_TYPE_SHORT, short_plmn_name);
1120                                         }
1121                                 }
1122                                 break;
1123
1124                         case AT_COPS_FORMAT_NUMERIC:
1125                                 if ((pResp = tcore_at_tok_nth(tokens, 2))) {
1126                                         dbg("numeric : %s", pResp);
1127                                         if (strlen(pResp) > 0) {
1128                                                 plmn_id = tcore_at_tok_extract((const char *)pResp);
1129
1130                                                 // set plmn id into po
1131                                                 tcore_network_set_plmn(o, plmn_id);
1132                                         }
1133                                 }
1134                                 break;
1135
1136                         default:
1137                                 break;
1138                         }
1139
1140                         // act
1141                         if ((pResp = tcore_at_tok_nth(tokens, 3))) {
1142                                 dbg("AcT  : %s", pResp);
1143                                 if (strlen(pResp) > 0) {
1144                                         AcT = atoi(pResp);
1145                                         tcore_network_set_access_technology(o, lookup_tbl_access_technology[AcT]);
1146                                 }
1147                         }
1148
1149                         tcore_at_tok_free(tokens);
1150                 }
1151
1152                 if(plmn_id)
1153                         memcpy(Tresp.plmn, plmn_id, strlen(plmn_id));
1154                 tcore_network_get_access_technology(o, &(Tresp.act));
1155                 tcore_network_get_lac(o, &(Tresp.gsm.lac));
1156
1157                 ur = tcore_pending_ref_user_request(p);
1158                 if (ur) {
1159                         Tresp.result = TCORE_RETURN_SUCCESS;
1160                         tcore_user_request_send_response(ur, TRESP_NETWORK_GET_SERVING_NETWORK, sizeof(struct tresp_network_get_serving_network), &Tresp);
1161                 } else {
1162                         /* Network change noti */
1163                         struct tnoti_network_change network_change;
1164
1165                         memset(&network_change, 0, sizeof(struct tnoti_network_change));
1166                         if(plmn_id)
1167                                 memcpy(network_change.plmn, plmn_id, strlen(plmn_id));
1168                         tcore_network_get_access_technology(o, &(network_change.act));
1169                         tcore_network_get_lac(o, &(network_change.gsm.lac));
1170
1171                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_pending_ref_plugin(p)), tcore_pending_ref_core_object(p),
1172                                                                                 TNOTI_NETWORK_CHANGE, sizeof(struct tnoti_network_change), &network_change);
1173                         dbg("dbg.. network_change.plmn  : %s", network_change.plmn);
1174                         dbg("dbg.. network_change.act  : %d", network_change.act);
1175                         dbg("dbg.. network_change.gsm.lac  : %d", network_change.gsm.lac);
1176
1177                         if ((AT_COPS_MODE_DEREGISTER != network_mode) &&
1178                                 (AT_COPS_MODE_SET_ONLY != network_mode)) {
1179                                 /*Network identity noti*/
1180                                 memset(&noti, 0x0, sizeof(struct tnoti_network_identity));
1181                                 if (long_plmn_name)
1182                                         memcpy(noti.full_name, long_plmn_name, MIN(32, strlen(long_plmn_name)));
1183                                 if (short_plmn_name)
1184                                         memcpy(noti.short_name, short_plmn_name, MIN(16, strlen(short_plmn_name)));
1185                                 if (plmn_id)
1186                                         memcpy(noti.plmn, plmn_id, strlen(plmn_id)); // plmn_id length is necessarily <= 6
1187
1188                                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)),
1189                                                                 o, TNOTI_NETWORK_IDENTITY, sizeof(struct tnoti_network_identity), &noti);
1190                                 dbg("dbg.. noti.short_name  : %s", noti.short_name);
1191                                 dbg("dbg.. noti.full_name  : %s", noti.full_name);
1192                                 dbg("dbg.. noti.plmn  : %s", noti.plmn);
1193                         }
1194                 }
1195
1196                 g_free(long_plmn_name);
1197                 g_free(short_plmn_name);
1198                 g_free(plmn_id);
1199         }
1200         return;
1201 }
1202
1203 static gboolean on_event_ps_network_regist(CoreObject *o, const void *data, void *user_data)
1204 {
1205         struct tnoti_network_registration_status regist_status;
1206         enum telephony_network_service_domain_status cs_status;
1207         enum telephony_network_service_domain_status ps_status;
1208         enum telephony_network_service_type service_type;
1209         enum telephony_network_access_technology act = NETWORK_ACT_UNKNOWN;
1210         struct tnoti_network_location_cellinfo net_lac_cell_info = {0};
1211         struct tnoti_ps_protocol_status noti = {0};
1212         unsigned char svc_domain = NETWORK_SERVICE_DOMAIN_PS;
1213         int stat = 0, AcT = 0;
1214         unsigned int lac = 0xffff, ci = 0xffff;
1215         unsigned int rac = 0xffff;
1216         GSList *tokens = NULL;
1217         char *pResp;
1218         char *line = NULL;
1219         GSList *lines = NULL;
1220
1221         lines = (GSList *) data;
1222         if (1 != g_slist_length(lines)) {
1223                 dbg("unsolicited msg but multiple line");
1224                 goto OUT;
1225         }
1226         line = (char *) (lines->data);
1227         dbg("+CGREG NOTI RECEIVED");
1228
1229 /*
1230 +CREG: <stat> [[,<lac>,<ci>[AcT]]
1231
1232 Possible values of <stat> can be
1233 0 Not registered, ME is not currently searching a new operator to register to
1234 1 Registered, home network
1235 2 Not registered, but ME is currently searching a new operator to register
1236 3 Registration denied
1237 4 Unknown
1238 5 Registered, in roaming
1239
1240 <lac>
1241 string type; two byte location area code in hexadecimal format (e.g. 00C3)
1242
1243 <ci>
1244 string type; four byte cell ID in hexadecimal format (e.g. 0000A13F)
1245
1246 <ACT>
1247 0 GSM
1248 2 UTRAN
1249 3 GSM w/EGPRS
1250 4 UTRAN w/HSDPA
1251 5 UTRAN w/HSUPA
1252 6 UTRAN w/HSDPA and HSUPA
1253 Note: <Act> is supporting from R7 and above Protocol Stack.
1254
1255 <rac>: is R7 and above feature, string type; one byte routing area code in hexadecimal format.
1256 */
1257         if (line != NULL) {
1258                 tokens = tcore_at_tok_new(line);
1259                 if (g_slist_length(tokens) < 1) {
1260                         msg("invalid message");
1261                         goto OUT;
1262                 }
1263
1264                 if (!(pResp = g_slist_nth_data(tokens, 0))) {
1265                         dbg("No  STAT in +CGREG");
1266                         goto OUT;
1267                 } else {
1268                         stat = atoi(pResp);
1269                         if ((pResp = g_slist_nth_data(tokens, 1))) {
1270                                 pResp = util_removeQuotes(pResp);
1271                                 lac = strtol(pResp, NULL, 16);
1272                                 g_free(pResp);
1273                         }
1274
1275                         if ((pResp = g_slist_nth_data(tokens, 2))) {
1276                                 pResp = util_removeQuotes(pResp);
1277                                 ci = strtol(pResp, NULL, 16);
1278                                 g_free(pResp);
1279                         } else {
1280                                 dbg("No ci in +CGREG");
1281                         }
1282
1283                         if ((pResp = g_slist_nth_data(tokens, 3)))
1284                                 AcT = atoi(pResp);
1285                         else
1286                                 dbg("No AcT in +CGREG");
1287
1288                         if ((pResp = g_slist_nth_data(tokens, 4))) {
1289                                 pResp = util_removeQuotes(pResp);
1290                                 rac = strtol(pResp, NULL, 16);
1291                                 g_free(pResp);
1292                         } else {
1293                                 dbg("No rac in +CGREG");
1294                         }
1295                 }
1296
1297
1298                 dbg("stat=%d, lac=0x%lx, ci=0x%lx, Act=%d, rac = 0x%x", stat, lac, ci, AcT, rac);
1299
1300                 ps_status = lookup_tbl_net_status[stat];
1301
1302                 tcore_network_set_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET, ps_status);
1303                 _ps_set(tcore_object_ref_plugin(o), ps_status);
1304
1305                 tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT, &cs_status);
1306
1307                 act = lookup_tbl_access_technology[AcT];
1308                 tcore_network_set_access_technology(o, act);
1309
1310                 if (stat == AT_CREG_STAT_REG_ROAM)
1311                         tcore_network_set_roaming_state(o, TRUE);
1312                 else
1313                         tcore_network_set_roaming_state(o, FALSE);
1314
1315                 tcore_network_get_service_type(o, &service_type);
1316                 dbg("prev_service_type = 0x%x", service_type);
1317                 service_type = _get_service_type(service_type, svc_domain, act, cs_status, ps_status);
1318                 dbg("new_service_type = 0x%x", service_type);
1319                 tcore_network_set_service_type(o, service_type);
1320
1321                 tcore_network_set_lac(o, lac);
1322                 tcore_network_set_cell_id(o, ci);
1323                 tcore_network_set_rac(o, rac);
1324
1325                 net_lac_cell_info.lac = lac;
1326                 net_lac_cell_info.cell_id = ci;
1327
1328                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_LOCATION_CELLINFO,
1329                                                                            sizeof(struct tnoti_network_location_cellinfo), &net_lac_cell_info);
1330
1331                 regist_status.cs_domain_status = cs_status;
1332                 regist_status.ps_domain_status = ps_status;
1333                 regist_status.service_type = service_type;
1334                 regist_status.roaming_status = tcore_network_get_roaming_state(o);
1335
1336                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
1337                                                                            TNOTI_NETWORK_REGISTRATION_STATUS, sizeof(regist_status), &regist_status);
1338 #if 0
1339                 if (service_type == NETWORK_SERVICE_TYPE_HSDPA)
1340                         noti.status = TELEPHONY_HSDPA_ON;
1341                 else
1342                         noti.status = TELEPHONY_HSDPA_OFF;
1343 #else
1344                 switch(AcT){
1345                         case AT_COPS_ACT_GSM:/*Fall Through*/
1346                         case AT_COPS_ACT_GSM_COMPACT:/*Fall Through*/
1347                         case AT_COPS_ACT_UTRAN:/*Fall Through*/
1348                         case AT_COPS_ACT_GSM_EGPRS:/*Fall Through*/
1349                         case AT_COPS_ACT_E_UTRAN:
1350                         {
1351                                 dbg("Not required for Protocol Status Notification");
1352                                 goto OUT;
1353                         }
1354                         case AT_COPS_ACT_UTRAN_HSDPA:
1355                         {
1356                                 dbg("HSDPA");
1357                                 noti.status = TELEPHONY_HSDPA_ON;
1358                                 break;
1359                         }
1360                         case AT_COPS_ACT_UTRAN_HSUPA:
1361                         {
1362                                 dbg("HSUPA");
1363                                 noti.status = TELEPHONY_HSUPA_ON;
1364                                 break;
1365                         }
1366                         case AT_COPS_ACT_UTRAN_HSDPA_HSUPA:
1367                         {
1368                                 dbg("HSPA");
1369                                 noti.status = TELEPHONY_HSPA_ON;
1370                                 break;
1371                         }
1372                         default:
1373                         {
1374                                 dbg("Ignore");
1375                                 goto OUT;
1376                         }
1377                 }
1378 #endif
1379                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_PS_PROTOCOL_STATUS,
1380                                                                            sizeof(struct tnoti_ps_protocol_status), &noti);
1381
1382                 /* Get PLMN ID needed to application */
1383                 // get_serving_network(o, NULL);
1384         } else {
1385                 dbg("Response NOK");
1386         }
1387
1388 OUT:
1389         if (NULL != tokens)
1390                 tcore_at_tok_free(tokens);
1391         return TRUE;
1392 }
1393
1394 static gboolean on_event_cs_network_regist(CoreObject *o, const void *event_info, void *user_data)
1395 {
1396         GSList *lines = NULL;
1397         char *line = NULL;
1398         struct tnoti_network_registration_status regist_status;
1399         enum telephony_network_service_domain_status cs_status;
1400         enum telephony_network_service_domain_status ps_status;
1401         enum telephony_network_service_type service_type;
1402         enum telephony_network_access_technology act = NETWORK_ACT_UNKNOWN;
1403         struct tnoti_network_location_cellinfo net_lac_cell_info = {0};
1404
1405
1406         unsigned char svc_domain = NETWORK_SERVICE_DOMAIN_CS;
1407         int stat = 0, AcT = 0;
1408         unsigned int lac = 0xffff, ci = 0xffff;
1409         GSList *tokens = NULL;
1410         char *pResp;
1411
1412         lines = (GSList *) event_info;
1413         if (1 != g_slist_length(lines)) {
1414                 dbg("unsolicited msg but multiple line");
1415                 goto OUT;
1416         }
1417         line = (char *) (lines->data);
1418
1419         dbg("+CREG NOTI RECEIVED");
1420
1421 /*
1422 +CREG: <stat> [[,<lac>,<ci>[AcT]]
1423
1424 Possible values of <stat> can be
1425 0 Not registered, ME is not currently searching a new operator to register to
1426 1 Registered, home network
1427 2 Not registered, but ME is currently searching a new operator to register
1428 3 Registration denied
1429 4 Unknown
1430 5 Registered, in roaming
1431
1432 <lac>
1433 string type; two byte location area code in hexadecimal format (e.g. 00C3)
1434
1435 <ci>
1436 string type; four byte cell ID in hexadecimal format (e.g. 0000A13F)
1437
1438 <ACT>
1439 0 GSM
1440 2 UTRAN
1441 3 GSM w/EGPRS
1442 4 UTRAN w/HSDPA
1443 5 UTRAN w/HSUPA
1444 6 UTRAN w/HSDPA and HSUPA
1445 Note: <Act> is supporting from R7 and above Protocol Stack.
1446 */
1447         if (line != NULL) {
1448                 tokens = tcore_at_tok_new(line);
1449                 if (g_slist_length(tokens) < 1) {
1450                         msg("invalid message");
1451                         goto OUT;
1452                 }
1453
1454                 if (!(pResp = g_slist_nth_data(tokens, 0))) {
1455                         dbg("No  STAT in +CREG");
1456                         goto OUT;
1457                 } else {
1458                         stat = atoi(pResp);
1459                         if ((pResp = g_slist_nth_data(tokens, 1))) {
1460                                 pResp = util_removeQuotes(pResp);
1461                                 lac = strtol(pResp, NULL, 16);
1462                                 g_free(pResp);
1463                         }
1464
1465                         if ((pResp = g_slist_nth_data(tokens, 2))) {
1466                                 pResp = util_removeQuotes(pResp);
1467                                 ci = strtol(pResp, NULL, 16);
1468                                 g_free(pResp);
1469                         } else {
1470                                 dbg("No ci in +CREG");
1471                         }
1472
1473                         if ((pResp = g_slist_nth_data(tokens, 3)))
1474                                 AcT = atoi(pResp);
1475                         else
1476                                 dbg("No AcT in +CREG");
1477                 }
1478
1479
1480                 dbg("stat=%d, lac=0x%lx, ci=0x%lx, Act=%d", stat, lac, ci, AcT);
1481
1482                 cs_status = lookup_tbl_net_status[stat];
1483                 tcore_network_set_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT, cs_status);
1484
1485                 // tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT, &cs_status);
1486                 tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET, &ps_status);
1487
1488                 act = lookup_tbl_access_technology[AcT];
1489                 tcore_network_set_access_technology(o, act);
1490
1491                 if (stat == AT_CREG_STAT_REG_ROAM)
1492                         tcore_network_set_roaming_state(o, TRUE);
1493                 else
1494                         tcore_network_set_roaming_state(o, FALSE);
1495
1496                 tcore_network_get_service_type(o, &service_type);
1497                 dbg("prev_service_type = 0x%x", service_type);
1498                 service_type = _get_service_type(service_type, svc_domain, act, cs_status, ps_status);
1499                 dbg("new_service_type = 0x%x", service_type);
1500                 tcore_network_set_service_type(o, service_type);
1501
1502                 tcore_network_set_lac(o, lac);
1503                 tcore_network_set_cell_id(o, ci);
1504
1505                 net_lac_cell_info.lac = lac;
1506                 net_lac_cell_info.cell_id = ci;
1507
1508                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_LOCATION_CELLINFO,
1509                                                                            sizeof(struct tnoti_network_location_cellinfo), &net_lac_cell_info);
1510
1511                 regist_status.cs_domain_status = cs_status;
1512                 regist_status.ps_domain_status = ps_status;
1513                 regist_status.service_type = service_type;
1514                 regist_status.roaming_status = tcore_network_get_roaming_state(o);
1515
1516                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
1517                                                                            TNOTI_NETWORK_REGISTRATION_STATUS, sizeof(struct tnoti_network_registration_status), &regist_status);
1518
1519                 /* Get PLMN ID needed to application */
1520                 if ((NETWORK_SERVICE_DOMAIN_STATUS_FULL == cs_status) ||
1521                         NETWORK_SERVICE_DOMAIN_STATUS_FULL == ps_status)
1522                         get_serving_network(o, NULL);
1523         } else {
1524                 dbg("Response NOK");
1525         }
1526
1527 OUT:
1528         if (NULL != tokens)
1529                 tcore_at_tok_free(tokens);
1530         return TRUE;
1531 }
1532
1533 static gboolean on_event_network_icon_info(CoreObject *o, const void *event_info, void *user_data)
1534 {
1535         struct tnoti_network_icon_info net_icon_info = {0};
1536         char *line = NULL;
1537         char *rssiToken = NULL;
1538         char *batteryToken = NULL;
1539         GSList *tokens = NULL;
1540         GSList *lines = NULL;
1541
1542         lines = (GSList *) event_info;
1543         if (1 != g_slist_length(lines)) {
1544                 dbg("unsolicited msg but multiple line");
1545                 goto OUT;
1546         }
1547         line = (char *) (lines->data);
1548         dbg("+XCIEV Network Icon Info Noti Recieve");
1549         memset(&net_icon_info, 0, sizeof(struct tnoti_network_icon_info));
1550
1551         if (line != NULL) {
1552                 dbg("Response OK");
1553
1554                 tokens = tcore_at_tok_new(line);
1555                 if (g_slist_length(tokens) != 2) {
1556                         msg("invalid message");
1557                         goto OUT;
1558                 }
1559
1560                 rssiToken = (char *) g_slist_nth_data(tokens, 0);
1561
1562                 if (strlen(rssiToken) > 0) {
1563                         net_icon_info.type = NETWORK_ICON_INFO_RSSI;
1564                         net_icon_info.rssi = atoi(g_slist_nth_data(tokens, 0));
1565                         dbg("rssi level : %d", net_icon_info.rssi);
1566                 }
1567
1568                 batteryToken = (char *) g_slist_nth_data(tokens, 1);
1569                 if (strlen(batteryToken) > 0) {
1570                         net_icon_info.type = NETWORK_ICON_INFO_BATTERY;
1571                         net_icon_info.battery = atoi(g_slist_nth_data(tokens, 1));
1572                         dbg("battery level : %d", net_icon_info.battery);
1573                 }
1574
1575                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_ICON_INFO,
1576                                                                            sizeof(struct tnoti_network_icon_info), &net_icon_info);
1577         } else {
1578                 dbg("Response NOK");
1579         }
1580
1581
1582 OUT:
1583         if (NULL != tokens)
1584                 tcore_at_tok_free(tokens);
1585
1586         return TRUE;
1587 }
1588
1589 static gboolean on_event_network_ctzv_time_info(CoreObject *o, const void *event_info, void *user_data)
1590 {
1591         struct tnoti_network_timeinfo net_time_info = {0};
1592         char *line = NULL;
1593         GSList *tokens = NULL;
1594         char *time = NULL;
1595         char *time_zone = NULL;
1596         GSList *lines = NULL;
1597         char ptime_param[20] = {0};
1598         UserRequest *ur = NULL;
1599         dbg("Enter : on_event_network_ctzv_time_info");
1600
1601         lines = (GSList *) event_info;
1602         if (1 != g_slist_length(lines)) {
1603                 dbg("unsolicited msg but multiple line");
1604                 goto OUT;
1605         }
1606         line = (char *) (lines->data);
1607
1608 /*
1609 +CTZV: <tz>,<time>
1610 <tz> integer value indicating the time zone (e.g. -22 or +34)
1611 <time> string type value; format is yy/MM/dd,hh:mms, wherein characters indicates year, month, day, hour,
1612 minutes, seconds.*/
1613
1614         dbg("Network time info (+CTZV) recieved");
1615
1616         if (line != NULL) {
1617                 dbg("Response OK");
1618                 dbg("noti line is %s", line);
1619
1620                 tokens = tcore_at_tok_new(line);
1621
1622                 if (g_slist_length(tokens) < 2) {
1623                         msg("invalid message");
1624                         goto OUT;
1625                 }
1626
1627                 if ((time_zone = g_slist_nth_data(tokens, 0))) {
1628                         net_time_info.gmtoff = atoi(time_zone) * 15; /* TZ in minutes */
1629                 }
1630
1631                 if (tcore_network_get_plmn(o) != NULL)
1632                         strcpy(net_time_info.plmn, tcore_network_get_plmn(o));
1633
1634                 if ((time = g_slist_nth_data(tokens, 1)) && (strlen(time) > 18)) {
1635                         strncpy(ptime_param, time + 1, 2); /* skip past initial quote (") */
1636                         net_time_info.year = atoi(ptime_param);
1637
1638                         strncpy(ptime_param, time + 4, 2); /* skip slash (/) after year param */
1639                         net_time_info.month = atoi(ptime_param);
1640
1641                         strncpy(ptime_param, time + 7, 2); /* skip past slash (/) after month param */
1642                         net_time_info.day = atoi(ptime_param);
1643
1644                         strncpy(ptime_param, time + 10, 2); /* skip past comma (,) after day param */
1645                         net_time_info.hour = atoi(ptime_param);
1646
1647                         strncpy(ptime_param, time + 13, 2); /* skip past colon (:) after hour param */
1648                         net_time_info.minute = atoi(ptime_param);
1649
1650                         strncpy(ptime_param, time + 16, 2); /* skip past colon (:) after minute param */
1651                         net_time_info.second = atoi(ptime_param);
1652                 }
1653                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_TIMEINFO, sizeof(struct tnoti_network_timeinfo), &net_time_info);
1654
1655                 dbg("new pending(AT+XOPS=0/5/6 for Nitz PLMN name)");
1656
1657                 /* Get NITZ name and plmn_id via AT+XCOPS = 0/5/6 */
1658                 nwk_prepare_and_send_pending_request(o, "AT+XCOPS=0;+XCOPS=5;+XCOPS=6", "+XCOPS", TCORE_AT_MULTILINE, ur, on_response_get_nitz_name);
1659         } else {
1660                 dbg("line is  NULL");
1661         }
1662
1663 OUT:
1664         if (NULL != tokens)
1665                 tcore_at_tok_free(tokens);
1666
1667         dbg("Exit: on_event_network_ctzv_time_info");
1668         return TRUE;
1669 }
1670
1671 static void on_sim_resp_hook_get_netname(UserRequest *ur, enum tcore_response_command command, unsigned int data_len,
1672                                                                                  const void *data, void *user_data)
1673 {
1674         const struct tresp_sim_read *resp = data;
1675         CoreObject *o = user_data;
1676
1677         if (command == TRESP_SIM_GET_SPN) {
1678                 dbg("OK SPN GETTING!!");
1679                 dbg("resp->result = 0x%x", resp->result);
1680                 dbg("resp->data.spn.display_condition = 0x%x", resp->data.spn.display_condition);
1681                 dbg("resp->data.spn.spn = [%s]", resp->data.spn.spn);
1682
1683                 tcore_network_set_network_name(o, TCORE_NETWORK_NAME_TYPE_SPN, (const char *) resp->data.spn.spn);
1684
1685                 /**
1686                  * display condition
1687                  *  bit[0]: 0 = display of registered PLMN name not required when registered PLMN is either HPLMN or a PLMN in the service provider PLMN list
1688                  *          1 = display of registered PLMN name required when registered PLMN is either HPLMN or a PLMN in the service provider PLMN list
1689                  *  bit[1]: 0 = display of the service provider name is required when registered PLMN is neither HPLMN nor a PLMN in the service provider PLMN list
1690                  *          1 = display of the service provider name is not required when registered PLMN is neither HPLMN nor a PLMN in the service provider PLMN list
1691                  */
1692                 if (resp->data.spn.display_condition & 0x01) {
1693                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_NETWORK);
1694                 }
1695                 if ((resp->data.spn.display_condition & 0x02) == 0) {
1696                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_SPN);
1697                 }
1698                 if ((resp->data.spn.display_condition & 0x03) == 0x01) {
1699                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_ANY);
1700                 }
1701
1702                 // fallback in case no SPN name is provided
1703                 if (resp->data.spn.spn[0] == '\0')
1704                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_NETWORK);
1705         }
1706 }
1707
1708 static enum tcore_hook_return on_hook_sim_init(Server *s, CoreObject *source, enum tcore_notification_command command,
1709                                                                                            unsigned int data_len, void *data, void *user_data)
1710 {
1711         const struct tnoti_sim_status *sim = data;
1712         UserRequest *ur = NULL;
1713
1714         if (sim->sim_status == SIM_STATUS_INIT_COMPLETED) {
1715                 ur = tcore_user_request_new(NULL, NULL);
1716                 tcore_user_request_set_command(ur, TREQ_SIM_GET_SPN);
1717                 tcore_user_request_set_response_hook(ur, on_sim_resp_hook_get_netname, user_data);
1718                 tcore_object_dispatch_request(source, ur);
1719         }
1720
1721         return TCORE_HOOK_RETURN_CONTINUE;
1722 }
1723
1724 static TReturn search_network(CoreObject *o, UserRequest *ur)
1725 {
1726         TcoreHal *h = NULL;
1727         TcorePending *pending = NULL;
1728         TcoreATRequest *atreq = NULL;
1729         char *cmd_str = NULL;
1730         dbg("search_network - ENTER!!");
1731
1732         if (!o || !ur)
1733                 return TCORE_RETURN_EINVAL;
1734
1735         h = tcore_object_get_hal(o);
1736         if(FALSE == tcore_hal_get_power_state(h)){
1737                 dbg("cp not ready/n");
1738                 return TCORE_RETURN_ENOSYS;
1739         }
1740
1741         pending = tcore_pending_new(o, 0);
1742
1743         cmd_str = g_strdup_printf("AT+COPS=?");
1744         atreq = tcore_at_request_new(cmd_str, "+COPS", TCORE_AT_SINGLELINE);
1745
1746         tcore_pending_set_request_data(pending, 0, atreq);
1747         tcore_pending_set_timeout(pending, 60);
1748         tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
1749         tcore_pending_set_response_callback(pending, on_response_search_network, NULL);
1750         tcore_pending_set_timeout_callback(pending, on_timeout_search_network, NULL);
1751         tcore_pending_link_user_request(pending, ur);
1752         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
1753
1754         tcore_hal_send_request(h, pending);
1755         g_free(cmd_str);
1756         return TCORE_RETURN_SUCCESS;
1757 }
1758
1759 static TReturn set_plmn_selection_mode(CoreObject *o, UserRequest *ur)
1760 {
1761         TcoreHal *h = NULL;
1762         TcorePending *pending = NULL;
1763         TcoreATRequest *atreq;
1764         char *cmd_str = NULL;
1765         int format = 0; /* default value for long alphanumeric */
1766         int mode = 0;
1767         char plmn[7] = {0};
1768         int act = 0;
1769
1770         const struct treq_network_set_plmn_selection_mode *req_data = NULL;
1771
1772
1773         dbg("set_plmn_selection_mode - ENTER!!");
1774
1775         if (!o || !ur)
1776                 return TCORE_RETURN_EINVAL;
1777
1778         req_data = tcore_user_request_ref_data(ur, NULL);
1779         h = tcore_object_get_hal(o);
1780         if(FALSE == tcore_hal_get_power_state(h)){
1781                 dbg("cp not ready/n");
1782                 return TCORE_RETURN_ENOSYS;
1783         }
1784         pending = tcore_pending_new(o, 0);
1785
1786         // Command Format - AT+COPS=[<mode>[,<format>[,<oper>[,< AcT>]]]]
1787         /* oper parameter format
1788             - 0 <oper> format presentations are set to long alphanumeric. If Network name not available it displays combination of Mcc and MNC in string format.
1789             - 1 <oper> format presentation is set to short alphanumeric.
1790             - 2 <oper> format presentations set to numeric.
1791         */
1792
1793         if ((req_data->act == NETWORK_ACT_GSM) || (req_data->act == NETWORK_ACT_EGPRS))
1794                 act = 0;
1795         else
1796                 act = 2;
1797
1798         switch (req_data->mode) {
1799         case NETWORK_SELECT_MODE_MANUAL:
1800         {
1801                 mode = AT_COPS_MODE_MANUAL;
1802                 format = AT_COPS_FORMAT_NUMERIC;
1803
1804                 memset(plmn, 0, 7);
1805                 memcpy(plmn, req_data->plmn, 6);
1806
1807                 if (strlen(req_data->plmn) == 6) {
1808                         if (plmn[5] == '#')
1809                                 plmn[5] = 0;
1810                 }
1811
1812                 cmd_str = g_strdup_printf("AT+COPS=%d,%d,\"%s\",%d", mode, format, plmn, act);
1813         }
1814         break;
1815
1816         case NETWORK_SELECT_MODE_AUTOMATIC:
1817         default:
1818                 cmd_str = g_strdup("AT+COPS=0");
1819                 break;
1820         }
1821
1822
1823         atreq = tcore_at_request_new(cmd_str, "+COPS", TCORE_AT_NO_RESULT);
1824
1825         tcore_pending_set_request_data(pending, 0, atreq);
1826         tcore_pending_set_response_callback(pending, on_response_set_plmn_selection_mode, NULL);
1827         tcore_pending_link_user_request(pending, ur);
1828         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
1829
1830         tcore_hal_send_request(h, pending);
1831         g_free(cmd_str);
1832         return TCORE_RETURN_SUCCESS;
1833 }
1834
1835 static TReturn get_plmn_selection_mode(CoreObject *o, UserRequest *ur)
1836 {
1837         TcoreHal *h = NULL;
1838         TcorePending *pending = NULL;
1839         TcoreATRequest *atreq;
1840         char *cmd_str = NULL;
1841
1842         dbg("get_plmn_selection_mode - ENTER!!");
1843
1844         if (!o || !ur)
1845                 return TCORE_RETURN_EINVAL;
1846
1847         h = tcore_object_get_hal(o);
1848         if(FALSE == tcore_hal_get_power_state(h)){
1849                 dbg("cp not ready/n");
1850                 return TCORE_RETURN_ENOSYS;
1851         }
1852         pending = tcore_pending_new(o, 0);
1853
1854         cmd_str = g_strdup_printf("AT+COPS?");
1855         atreq = tcore_at_request_new(cmd_str, "+COPS", TCORE_AT_SINGLELINE);
1856
1857         tcore_pending_set_request_data(pending, 0, atreq);
1858         tcore_pending_set_response_callback(pending, on_response_get_plmn_selection_mode, NULL);
1859         tcore_pending_link_user_request(pending, ur);
1860         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
1861
1862         tcore_hal_send_request(h, pending);
1863         g_free(cmd_str);
1864         return TCORE_RETURN_SUCCESS;
1865 }
1866
1867
1868 static TReturn set_band(CoreObject *o, UserRequest *ur)
1869 {
1870         TcoreHal *h = NULL;
1871         TcorePending *pending = NULL;
1872         TcorePending *pending_gsm = NULL;
1873         TcorePending *pending_umts = NULL;
1874         TcoreATRequest *atreq;
1875         char *cmd_str = NULL;
1876         const struct treq_network_set_band *req_data;
1877         gboolean set_gsm_band = 0;
1878         gboolean set_umts_band = 0;
1879         int gsm_band = 255;
1880         int gsm_band2 = 255;
1881         char *umts_band = NULL;
1882         UserRequest *dup_ur_gsm = NULL;
1883         UserRequest *dup_ur_umts = NULL;
1884
1885         dbg("set_band - ENTER!!");
1886
1887         if (!o || !ur)
1888                 return TCORE_RETURN_EINVAL;
1889
1890         req_data = tcore_user_request_ref_data(ur, NULL);
1891         h = tcore_object_get_hal(o);
1892         if(FALSE == tcore_hal_get_power_state(h)){
1893                 dbg("cp not ready/n");
1894                 return TCORE_RETURN_ENOSYS;
1895         }
1896
1897         dbg("set_band - called with band = %d", req_data->band);
1898
1899         switch (req_data->band) {
1900         case NETWORK_BAND_TYPE_GSM850:
1901                 gsm_band = AT_GSM_XBANDSEL_850;
1902                 set_gsm_band = TRUE;
1903                 break;
1904
1905         case NETWORK_BAND_TYPE_GSM_900_1800:
1906                 gsm_band = AT_GSM_XBANDSEL_900;
1907                 gsm_band2 = AT_GSM_XBANDSEL_1800;
1908                 set_gsm_band = TRUE;
1909                 break;
1910
1911         case NETWORK_BAND_TYPE_GSM1900:
1912                 gsm_band = AT_GSM_XBANDSEL_1900;
1913                 set_gsm_band = TRUE;
1914                 break;
1915
1916         case NETWORK_BAND_TYPE_GSM1800:
1917                 gsm_band = AT_GSM_XBANDSEL_1800;
1918                 set_gsm_band = TRUE;
1919                 break;
1920
1921         case NETWORK_BAND_TYPE_GSM_850_1900:
1922                 gsm_band = AT_GSM_XBANDSEL_850;
1923                 gsm_band2 = AT_GSM_XBANDSEL_1900;
1924                 set_gsm_band = TRUE;
1925                 break;
1926
1927         case NETWORK_BAND_TYPE_ANY:
1928                 gsm_band = AT_GSM_XBANDSEL_AUTOMATIC;
1929                 set_umts_band = TRUE;
1930                 set_gsm_band = TRUE;
1931                 break;
1932
1933         case NETWORK_BAND_TYPE_WCDMA:
1934                 set_umts_band = TRUE;
1935                 break;
1936
1937         case NETWORK_BAND_TYPE_WCDMA2100:
1938                 umts_band = "UMTS_BAND_I";
1939                 set_umts_band = TRUE;
1940                 break;
1941
1942         case NETWORK_BAND_TYPE_WCDMA1900:
1943                 umts_band = "UMTS_BAND_II";
1944                 set_umts_band = TRUE;
1945                 break;
1946
1947         case NETWORK_BAND_TYPE_WCDMA850:
1948                 umts_band = "UMTS_BAND_V";
1949                 set_umts_band = TRUE;
1950                 break;
1951
1952         default:
1953                 break;
1954         }
1955
1956         dbg("set_band > set_umts_band = %d, set_gsm_band = %d", set_umts_band, set_gsm_band);
1957
1958         if (set_umts_band == TRUE) {
1959                 if ((req_data->band == NETWORK_BAND_TYPE_WCDMA) || (req_data->band == NETWORK_BAND_TYPE_ANY))
1960                         cmd_str = g_strdup_printf("AT+XUBANDSEL=0");
1961                 else
1962                         cmd_str = g_strdup_printf("AT+XUBANDSEL=%s", umts_band);
1963
1964                 atreq = tcore_at_request_new(cmd_str, "+XUBANDSEL", TCORE_AT_NO_RESULT);
1965                 pending_umts = tcore_pending_new(o, 0);
1966
1967                 tcore_pending_set_request_data(pending_umts, 0, atreq);
1968                 tcore_pending_set_priority(pending_umts, TCORE_PENDING_PRIORITY_DEFAULT);
1969                 tcore_pending_set_response_callback(pending_umts, on_response_set_umts_band, NULL);
1970
1971                 /* duplicate user request for UMTS Band setting AT command for same UR */
1972                 dup_ur_umts = tcore_user_request_ref(ur);
1973                 tcore_pending_link_user_request(pending_umts, dup_ur_umts);
1974                 tcore_pending_set_send_callback(pending_umts, on_confirmation_network_message_send, NULL);
1975
1976                 tcore_hal_send_request(h, pending_umts);
1977                 g_free(cmd_str);
1978         }
1979
1980         if (set_gsm_band == TRUE) {
1981                 dbg("Entered set_gsm_band");
1982                 if (gsm_band2 == 255)
1983                         cmd_str = g_strdup_printf("AT+XBANDSEL=%d", gsm_band);
1984                 else
1985                         cmd_str = g_strdup_printf("AT+XBANDSEL=%d,%d", gsm_band, gsm_band2);
1986
1987                 dbg("Command string: %s", cmd_str);
1988                 atreq = tcore_at_request_new(cmd_str, "+XBANDSEL", TCORE_AT_NO_RESULT);
1989                 pending_gsm = tcore_pending_new(o, 0);
1990
1991                 tcore_pending_set_request_data(pending_gsm, 0, atreq);
1992                 tcore_pending_set_priority(pending_gsm, TCORE_PENDING_PRIORITY_DEFAULT);
1993                 tcore_pending_set_response_callback(pending_gsm, on_response_set_gsm_band, NULL);
1994
1995                 /* duplicate user request for GSM Band setting AT command for same UR */
1996                 dup_ur_gsm = tcore_user_request_ref(ur);
1997                 tcore_pending_link_user_request(pending_gsm, dup_ur_gsm);
1998                 tcore_pending_set_send_callback(pending_gsm, on_confirmation_network_message_send, NULL);
1999
2000                 tcore_hal_send_request(h, pending_gsm);
2001                 g_free(cmd_str);
2002         }
2003
2004         /* Lock device to specific RAT as requested by application */
2005 /*
2006 AT+XRAT=<Act>[,<PreferredAct>]
2007 <AcT> indicates the radio access technology and may be
2008 0 GSM single mode
2009 1 GSM / UMTS Dual mode
2010 2 UTRAN (UMTS)
2011 */
2012         if ((set_umts_band == TRUE) && (set_gsm_band == TRUE)) {
2013                 cmd_str = g_strdup_printf("AT+XRAT=%d", AT_XRAT_DUAL);
2014         } else if (set_umts_band == TRUE) {
2015                 cmd_str = g_strdup_printf("AT+XRAT=%d", AT_XRAT_UMTS);
2016         } else {
2017                 cmd_str = g_strdup_printf("AT+XRAT=%d", AT_XRAT_GSM);
2018         }
2019         atreq = tcore_at_request_new(cmd_str, "+XRAT", TCORE_AT_NO_RESULT);
2020         pending = tcore_pending_new(o, 0);
2021
2022         tcore_pending_set_request_data(pending, 0, atreq);
2023         tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
2024         tcore_pending_set_response_callback(pending, on_response_set_xrat, NULL);
2025         tcore_pending_link_user_request(pending, ur);
2026         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
2027
2028         tcore_hal_send_request(h, pending);
2029         g_free(cmd_str);
2030         return TCORE_RETURN_SUCCESS;
2031 }
2032
2033 static TReturn get_band(CoreObject *o, UserRequest *ur)
2034 {
2035         TcoreHal *h = NULL;
2036         TcorePending *pending = NULL;
2037         TcoreATRequest *atreq;
2038         char *cmd_str = NULL;
2039         dbg("get_band - ENTER!!");
2040
2041         if (!o || !ur)
2042                 return TCORE_RETURN_EINVAL;
2043
2044         h = tcore_object_get_hal(o);
2045         if(FALSE == tcore_hal_get_power_state(h)){
2046                 dbg("cp not ready/n");
2047                 return TCORE_RETURN_ENOSYS;
2048         }
2049
2050         /* Get RAT Information Information. Based on RAT read response, we will get specific RAT bands only */
2051         cmd_str = g_strdup_printf("AT+XRAT?");
2052         atreq = tcore_at_request_new(cmd_str, "+XRAT", TCORE_AT_SINGLELINE);
2053         pending = tcore_pending_new(o, 0);
2054         tcore_pending_set_request_data(pending, 0, atreq);
2055         tcore_pending_set_response_callback(pending, on_response_get_xrat, NULL);
2056         tcore_pending_link_user_request(pending, ur);
2057         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
2058         tcore_hal_send_request(h, pending);
2059
2060         g_free(cmd_str);
2061         return TCORE_RETURN_SUCCESS;
2062 }
2063
2064 static TReturn set_preferred_plmn(CoreObject *o, UserRequest *ur)
2065 {
2066         TcoreHal *h = NULL;
2067         TcorePlugin *p = NULL;
2068         TcorePending *pending = NULL;
2069         TcoreATRequest *atreq = NULL;
2070         struct treq_network_set_preferred_plmn *req_data = NULL;
2071         char *cmd_str = NULL;
2072         int format = 2; /* Alway use numeric format, as application gives data in this default format */
2073         int gsm_act = 0;
2074         int gsm_compact_act = 0;
2075         int utran_act = 0;
2076
2077         if (!o || !ur)
2078                 return TCORE_RETURN_EINVAL;
2079
2080         p = tcore_object_ref_plugin(o);
2081         h = tcore_object_get_hal(o);
2082         if(FALSE == tcore_hal_get_power_state(h)){
2083                 dbg("cp not ready/n");
2084                 return TCORE_RETURN_ENOSYS;
2085         }
2086
2087         req_data = (struct treq_network_set_preferred_plmn *) tcore_user_request_ref_data(ur, NULL);
2088         pending = tcore_pending_new(o, 0);
2089
2090         dbg("Entry set_preferred_plmn");
2091 /*
2092 AT+CPOL=
2093 [<index>][,<format>[,<oper>[,<GSM_AcT>,
2094 <GSM_Compact_AcT>,<UTRAN_AcT>]]]
2095  */
2096
2097         if ((req_data->act == NETWORK_ACT_GSM) || (req_data->act == NETWORK_ACT_GPRS) || (req_data->act == NETWORK_ACT_EGPRS))
2098                 gsm_act = TRUE;
2099         else if ((req_data->act == NETWORK_ACT_UMTS) || (req_data->act == NETWORK_ACT_UTRAN))
2100                 utran_act = TRUE;
2101         else if (req_data->act == NETWORK_ACT_GSM_UTRAN)
2102                 gsm_act = utran_act = TRUE;
2103
2104         if (strlen(req_data->plmn) > 6) {
2105                 req_data->plmn[6] = '\0';
2106         } else if (strlen(req_data->plmn) == 6) {
2107                 if (req_data->plmn[5] == '#') {
2108                         req_data->plmn[5] = '\0';
2109                 }
2110         }
2111         cmd_str = g_strdup_printf("AT+CPOL=%d,%d,\"%s\",%d,%d,%d", req_data->index + 1, format, req_data->plmn, gsm_act, gsm_compact_act, utran_act);
2112
2113         dbg("cmd_str - %s", cmd_str);
2114         atreq = tcore_at_request_new(cmd_str, "+CPOL", TCORE_AT_NO_RESULT);
2115
2116         tcore_pending_set_request_data(pending, 0, atreq);
2117         tcore_pending_set_response_callback(pending, on_response_set_preferred_plmn, NULL);
2118         tcore_pending_link_user_request(pending, ur);
2119         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
2120
2121         tcore_hal_send_request(h, pending);
2122
2123         g_free(cmd_str);
2124
2125         dbg("Exit set_preferred_plmn");
2126
2127         return TCORE_RETURN_SUCCESS;
2128 }
2129
2130 static TReturn get_preferred_plmn(CoreObject *o, UserRequest *ur)
2131 {
2132         TcoreHal *h = NULL;
2133         TcorePending *pending = NULL;
2134         TcoreATRequest *atreq = NULL;
2135
2136         char *cmd_str = NULL;
2137
2138         dbg("get_preferred_plmn - ENTER!!");
2139
2140         if (!o || !ur)
2141                 return TCORE_RETURN_EINVAL;
2142
2143         h = tcore_object_get_hal(o);
2144         if(FALSE == tcore_hal_get_power_state(h)){
2145                 dbg("cp not ready/n");
2146                 return TCORE_RETURN_ENOSYS;
2147         }
2148
2149         pending = tcore_pending_new(o, 0);
2150
2151         cmd_str = g_strdup_printf("AT+CPOL=,2;+CPOL?");
2152         atreq = tcore_at_request_new(cmd_str, "+CPOL", TCORE_AT_MULTILINE);
2153
2154         tcore_pending_set_request_data(pending, 0, atreq);
2155         tcore_pending_set_response_callback(pending, on_response_get_preferred_plmn, NULL);
2156         tcore_pending_link_user_request(pending, ur);
2157         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
2158
2159         tcore_hal_send_request(h, pending);
2160
2161         g_free(cmd_str);
2162
2163         dbg("get_preferred_plmn - EXIT!!");
2164
2165         return TCORE_RETURN_SUCCESS;
2166 }
2167
2168 static TReturn get_serving_network(CoreObject *o, UserRequest *ur)
2169 {
2170         dbg("get_serving_network - ENTER!!");
2171
2172         if (!o)
2173                 return TCORE_RETURN_EINVAL;
2174
2175         if(FALSE == tcore_hal_get_power_state(tcore_object_get_hal(o))){
2176                 dbg("cp not ready/n");
2177                 return TCORE_RETURN_ENOSYS;
2178         }
2179
2180         dbg("new pending(AT+COPS?)");
2181
2182         nwk_prepare_and_send_pending_request(o, "AT+COPS=3,2;+COPS?;+COPS=3,0;+COPS?", "+COPS", TCORE_AT_MULTILINE, ur, on_response_get_serving_network);
2183         return TCORE_RETURN_SUCCESS;
2184 }
2185
2186 static struct tcore_network_operations network_ops = {
2187         .search = search_network,
2188         .set_plmn_selection_mode = set_plmn_selection_mode,
2189         .get_plmn_selection_mode = get_plmn_selection_mode,
2190         .set_service_domain = NULL,
2191         .get_service_domain = NULL,
2192         .set_band = set_band,
2193         .get_band = get_band,
2194         .set_preferred_plmn = set_preferred_plmn,
2195         .get_preferred_plmn = get_preferred_plmn,
2196         .set_order = NULL,
2197         .get_order = NULL,
2198         .set_power_on_attach = NULL,
2199         .get_power_on_attach = NULL,
2200         .set_cancel_manual_search = NULL,
2201         .get_serving_network = get_serving_network,
2202 };
2203
2204 gboolean s_network_init(TcorePlugin *cp, CoreObject *co_network)
2205 {
2206         dbg("Enter");
2207
2208         tcore_network_override_ops(co_network, &network_ops);
2209
2210         tcore_object_override_callback(co_network, "+CREG", on_event_cs_network_regist, NULL);
2211         tcore_object_override_callback(co_network, "+CGREG", on_event_ps_network_regist, NULL);
2212         tcore_object_override_callback(co_network, "+XCIEV", on_event_network_icon_info, NULL);
2213
2214         /* +CTZV: <tz>,<time> */
2215         tcore_object_override_callback(co_network, "+CTZV", on_event_network_ctzv_time_info, NULL);
2216
2217         tcore_server_add_notification_hook(tcore_plugin_ref_server(cp), TNOTI_SIM_STATUS, on_hook_sim_init, co_network);
2218
2219         _insert_mcc_mnc_oper_list(cp, co_network);
2220
2221         dbg("Exit");
2222
2223         return TRUE;
2224 }
2225
2226 void s_network_exit(TcorePlugin *cp, CoreObject *co_network)
2227 {
2228         dbg("Exit");
2229 }