Revert manifest to default one
[profile/ivi/tel-plugin-atmodem.git] / src / s_network.c
1 /*
2  * tel-plugin-atmodem
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hayoon Ko <hayoon.ko@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 #include <glib.h>
25
26 #define FEATURE_SAMSUNG_ONEDRAM
27
28 #include <tcore.h>
29 #include <hal.h>
30 #include <core_object.h>
31 #include <plugin.h>
32 #include <queue.h>
33 #include <co_ps.h>
34 #include <co_network.h>
35 #include <server.h>
36 #include <storage.h>
37
38 #include "s_common.h"
39 #include "s_network.h"
40 #include "atchannel.h"
41 #include "at_tok.h"
42
43 extern struct ATResponse *sp_response;
44 extern char *s_responsePrefix;
45 extern enum ATCommandType s_type;
46
47 #define AT_CREG_STAT_NOT_REG    0 /* not registered, MT is not currently searching a new operator to register to */
48 #define AT_CREG_STAT_REG_HOME   1 /* registered, home network */
49 #define AT_CREG_STAT_SEARCHING  2 /* not registered, but MT is currently searching a new operator to register to */
50 #define AT_CREG_STAT_REG_DENIED 3 /* registration denied */
51 #define AT_CREG_STAT_UNKNOWN    4 /* unknown */
52 #define AT_CREG_STAT_REG_ROAM   5 /* registered, roaming */
53
54 static unsigned int lookup_tbl_net_status[] = {
55         [AT_CREG_STAT_NOT_REG]  = NETWORK_SERVICE_DOMAIN_STATUS_NO,
56         [AT_CREG_STAT_REG_HOME] = NETWORK_SERVICE_DOMAIN_STATUS_FULL,
57         [AT_CREG_STAT_SEARCHING]        = NETWORK_SERVICE_DOMAIN_STATUS_SEARCH,
58         [AT_CREG_STAT_REG_DENIED]       = NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY,
59         [AT_CREG_STAT_UNKNOWN]  = NETWORK_SERVICE_DOMAIN_STATUS_NO,
60         [AT_CREG_STAT_REG_ROAM] = NETWORK_SERVICE_DOMAIN_STATUS_FULL,
61 };
62
63 #define AT_COPS_MODE_AUTOMATIC  0 /* automatic (<oper> field is ignored) */
64 #define AT_COPS_MODE_MANUAL     1 /* manual (<oper> field shall be present, and <AcT> optionally) */
65 #define AT_COPS_MODE_DEREGISTER 2 /* deregister from network */
66 #define AT_COPS_MODE_SET_ONLY   3 /* set only <format> */
67
68 #define AT_COPS_FORMAT_LONG_ALPHANUMERIC        0 /* long format alphanumeric <oper> */
69 #define AT_COPS_FORMAT_SHORT_ALPHANUMERIC       1 /* short format alphanumeric <oper> */
70 #define AT_COPS_FORMAT_NUMERIC                  2 /* numeric <oper> */
71
72 #define AT_COPS_ACT_GSM                 0       /* GSM */
73 #define AT_COPS_ACT_GSM_COMPACT         1       /* GSM Compact */
74 #define AT_COPS_ACT_UTRAN               2       /* UTRAN */
75 #define AT_COPS_ACT_GSM_EGPRS           3       /* GSM w/EGPRS */
76 #define AT_COPS_ACT_UTRAN_HSDPA         4       /* UTRAN w/HSDPA */
77 #define AT_COPS_ACT_UTRAN_HSUPA         5       /* UTRAN w/HSUPA */
78 #define AT_COPS_ACT_UTRAN_HSDPA_HSUPA   6       /* UTRAN w/HSDPA and HSUPA */
79 #define AT_COPS_ACT_E_UTRAN             7       /* E-UTRAN */
80
81 static unsigned int lookup_tbl_access_technology[] = {
82         [AT_COPS_ACT_GSM]               = NETWORK_ACT_GSM,
83         [AT_COPS_ACT_GSM_COMPACT]       = NETWORK_ACT_GSM,
84         [AT_COPS_ACT_UTRAN]             = NETWORK_ACT_UTRAN,
85         [AT_COPS_ACT_GSM_EGPRS]         = NETWORK_ACT_EGPRS,
86         [AT_COPS_ACT_UTRAN_HSDPA]       = NETWORK_ACT_UTRAN,
87         [AT_COPS_ACT_UTRAN_HSUPA]       = NETWORK_ACT_UTRAN,
88         [AT_COPS_ACT_UTRAN_HSDPA_HSUPA] = NETWORK_ACT_UTRAN,
89         [AT_COPS_ACT_E_UTRAN]           = NETWORK_ACT_GSM_UTRAN,
90 };
91 static unsigned int current_lac=0;
92 static gboolean get_serving_network(CoreObject *o, UserRequest *ur);
93 static void on_confirmation_network_message_send( TcorePending *pending, gboolean result, void *user_data );
94
95 static void __set_metainfo(UserRequest *ur, struct ATReqMetaInfo *info, enum ATCommandType type, char *prefix)
96 {
97         if (!info || !ur)
98                 return;
99         memset(info, 0, sizeof(struct ATReqMetaInfo));
100         info->type = type;
101         if (!prefix)
102                 info->responsePrefix[0] ='\0';
103         else
104                 memcpy(info->responsePrefix, prefix, strlen(prefix));
105         tcore_user_request_set_metainfo(ur, sizeof(struct ATReqMetaInfo), info);
106 }
107 static void __send_at_request(CoreObject *o, char* atcmd, UserRequest *ur, TcorePendingResponseCallback func)
108 {
109         TcorePlugin *plugin = NULL;
110         TcoreHal *hal = NULL;
111         TcorePending *pending = NULL;
112
113         plugin = tcore_object_ref_plugin(o);
114         hal = tcore_object_get_hal(o);
115
116         pending = tcore_pending_new(o, ID_RESERVED_AT);
117         tcore_pending_set_request_data(pending, strlen(atcmd), atcmd);
118         tcore_pending_set_timeout(pending, 0);
119         tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
120         tcore_pending_set_response_callback(pending, func, NULL);
121         tcore_pending_link_user_request(pending, ur);
122
123         tcore_pending_set_send_callback(pending, on_confirmation_network_message_send, NULL);
124
125         tcore_hal_send_request(hal, pending);
126 }
127
128 static void _insert_mcc_mnc_oper_list(TcorePlugin *plugin, CoreObject *o)
129 {
130         Server *s;
131         Storage *strg;
132         void *handle;
133         char query[255] = {     0, };
134         GHashTableIter iter;
135         gpointer key, value;
136         GHashTable *result = NULL, *row = NULL;
137         struct tcore_network_operator_info *noi = NULL;
138         int count = 0;
139
140         s = tcore_plugin_ref_server(plugin);
141         strg = tcore_server_find_storage(s, "database");
142
143         handle = tcore_storage_create_handle(strg, "/opt/dbspace/.mcc_mnc_oper_list.db");
144         if (!handle) {
145                 dbg("fail to create database handle");
146                 return;
147         }
148
149         snprintf(query, 255, "select country, mcc, mnc, oper from mcc_mnc_oper_list");
150
151         result = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
152                         (GDestroyNotify) g_hash_table_destroy);
153
154         tcore_storage_read_query_database(strg, handle, query, NULL, result, 4);
155
156         g_hash_table_iter_init(&iter, result);
157         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
158                 row = value;
159
160                 noi = calloc(sizeof(struct tcore_network_operator_info), 1);
161
162                 snprintf(noi->mcc, 4, "%s",(const gchar *)(g_hash_table_lookup(row, "1")));
163                 snprintf(noi->mnc, 4, "%s",(const gchar *)(g_hash_table_lookup(row, "2")));
164                 snprintf(noi->name, 41, "%s",(const gchar *)(g_hash_table_lookup(row, "3")));
165                 snprintf(noi->country, 4, "%s",(const gchar *)(g_hash_table_lookup(row, "0")));
166
167                 tcore_network_operator_info_add(o, noi);
168
169                 count++;
170         }
171
172         dbg("count = %d", count);
173
174         g_hash_table_destroy(result);
175
176         tcore_storage_remove_handle(strg, handle);
177 }
178
179
180 static gboolean _is_cdma(int act)
181 {
182         switch (act) {
183                 case NETWORK_ACT_IS95A:
184                 case NETWORK_ACT_IS95B:
185                 case NETWORK_ACT_CDMA_1X:
186                 case NETWORK_ACT_EVDO_REV0:
187                 case NETWORK_ACT_CDMA_1X_EVDO_REV0:
188                 case NETWORK_ACT_EVDO_REVA:
189                 case NETWORK_ACT_CDMA_1X_EVDO_REVA:
190                 case NETWORK_ACT_EVDV:
191                         return TRUE;
192                         break;
193         }
194
195         return FALSE;
196 }
197
198 static enum telephony_network_service_type _get_service_type(enum telephony_network_service_type prev_type,
199                 int domain, int act, int cs_status, int ps_status)
200 {
201         enum telephony_network_service_type ret;
202
203         ret = prev_type;
204
205         switch (act) {
206                 case NETWORK_ACT_NOT_SPECIFIED:
207                         ret = NETWORK_SERVICE_TYPE_UNKNOWN;
208                         break;
209
210                 case NETWORK_ACT_GSM:
211                         if (prev_type == NETWORK_SERVICE_TYPE_2_5G_EDGE && domain == NETWORK_SERVICE_DOMAIN_CS)
212                                 ret = NETWORK_SERVICE_TYPE_2_5G_EDGE;
213                         else
214                                 ret = NETWORK_SERVICE_TYPE_2G;
215                         break;
216
217                 case NETWORK_ACT_IS95A:
218                 case NETWORK_ACT_IS95B:
219                         ret = NETWORK_SERVICE_TYPE_2G;
220                         break;
221
222                 case NETWORK_ACT_CDMA_1X:
223                 case NETWORK_ACT_GPRS:
224                         ret = NETWORK_SERVICE_TYPE_2_5G;
225                         break;
226
227                 case NETWORK_ACT_EGPRS:
228                         return NETWORK_SERVICE_TYPE_2_5G_EDGE;
229                         break;
230
231                 case NETWORK_ACT_UMTS:
232                         ret = NETWORK_SERVICE_TYPE_3G;
233                         break;
234
235                 case NETWORK_ACT_EVDO_REV0:
236                 case NETWORK_ACT_CDMA_1X_EVDO_REV0:
237                 case NETWORK_ACT_EVDO_REVA:
238                 case NETWORK_ACT_CDMA_1X_EVDO_REVA:
239                 case NETWORK_ACT_EVDV:
240                         ret = NETWORK_SERVICE_TYPE_3G;
241                         break;
242         }
243
244         if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_NO && ps_status == NETWORK_SERVICE_DOMAIN_STATUS_NO) {
245                 ret = NETWORK_SERVICE_TYPE_NO_SERVICE;
246         }
247         else if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_SEARCH || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_SEARCH) {
248                 if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
249                         /* no change */
250                 }
251                 else {
252                         ret = NETWORK_SERVICE_TYPE_SEARCH;
253                 }
254         }
255         else if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY) {
256                 if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL || ps_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
257                         /* no change */
258                 }
259                 else {
260                         ret = NETWORK_SERVICE_TYPE_EMERGENCY;
261                 }
262         }
263
264         return ret;
265 }
266
267 static void _ps_set(TcorePlugin *plugin, int status)
268 {
269         GSList *co_list = NULL;
270
271         co_list = tcore_plugin_get_core_objects_bytype(plugin, CORE_OBJECT_TYPE_PS);
272         do {
273                 CoreObject *o = NULL;
274                 o = (CoreObject *) co_list->data;
275                 if (!o)
276                         break;
277
278                 if (status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
279                         tcore_ps_set_online(o, TRUE);
280                 }
281                 else {
282                         tcore_ps_set_online(o, FALSE);
283                 }
284         } while ((co_list = g_slist_next(co_list)));
285
286         g_slist_free(co_list);
287 }
288
289 static TReturn _network_general_response_result(void)
290 {
291         if (sp_response->success > 0) {
292                 ReleaseResponse();
293                 return TCORE_RETURN_SUCCESS;
294         }
295         else {
296                 int ret, error;
297                 char* line=NULL;
298                 line = sp_response->finalResponse;
299                 ret = at_tok_start(&line);
300                 if (ret < 0) {
301                         err("err cause not specified or string corrupted");
302                         ReleaseResponse();
303                         return TCORE_RETURN_3GPP_ERROR;
304                 }
305                 else {
306                         ret = at_tok_nextint(&line, &error);
307                         if (ret < 0) {
308                                 err("err not specified or string not contail error");
309                                 ReleaseResponse();
310                                 return TCORE_RETURN_3GPP_ERROR;
311
312                         }
313                         else {
314                                 ReleaseResponse();
315                                 return convertCMEError((enum ATCMEError)error);
316                         }
317                 }
318         }
319 }
320
321 static void on_confirmation_network_message_send( TcorePending *pending, gboolean result, void *user_data )
322 {
323         UserRequest* ur = NULL;
324         struct ATReqMetaInfo* metainfo = NULL;
325         unsigned int info_len =0;
326         dbg("AT msg goes out from queue. Allocate ATRsp buffer and write rspPrefix\n");
327
328         ReleaseResponse();
329         sp_response = at_response_new();
330
331         ur = tcore_pending_ref_user_request(pending);
332         metainfo = (struct ATReqMetaInfo*)tcore_user_request_ref_metainfo(ur,&info_len);
333
334         if ((metainfo->type == SINGLELINE) || (metainfo->type == MULTILINE)) {
335                 s_responsePrefix = strdup(metainfo->responsePrefix);
336                 dbg("duplicating responsePrefix : %s\n", s_responsePrefix);
337         }
338         else {
339                 s_responsePrefix = NULL;
340         }
341
342         s_type = metainfo->type;
343
344         if (result == FALSE) {
345                 dbg("SEND FAIL");
346         }
347         else {
348                 dbg("SEND OK");
349         }
350 }
351
352 static void on_response_set_plmn_selection_mode(TcorePending *pending, int data_len, const void *data, void *user_data)
353 {
354         UserRequest *ur;
355         struct tresp_network_set_plmn_selection_mode resp;
356
357         dbg("RESPONSE OK");
358
359         resp.result = _network_general_response_result();
360
361         ur = tcore_pending_ref_user_request(pending);
362         if (ur) {
363                 tcore_user_request_send_response(ur, TRESP_NETWORK_SET_PLMN_SELECTION_MODE, sizeof(struct tresp_network_set_plmn_selection_mode), &resp);
364         }
365 }
366
367 static void on_response_get_plmn_selection_mode(TcorePending *pending, int data_len, const void *data, void *user_data)
368 {
369         UserRequest *ur;
370         struct tresp_network_get_plmn_selection_mode resp = {0};
371         char* line=NULL;
372         int mode=0;
373         int ret;
374
375         printResponse();
376
377         if (sp_response->success > 0) {
378                 dbg("RESPONSE OK");
379                 line = sp_response->p_intermediates->line;
380                 ret = at_tok_start(&line);
381                 if (ret < 0)
382                         AT_TOK_ERROR(line);
383
384                 ret = at_tok_nextint(&line,&mode);
385                 if (ret < 0)
386                         AT_TOK_ERROR(line);
387
388                 dbg("mode = %d", mode);
389                 switch(mode) {
390                         case AT_COPS_MODE_AUTOMATIC:
391                                 resp.mode = NETWORK_SELECT_MODE_GLOBAL_AUTOMATIC;
392                         break;
393                         case AT_COPS_MODE_MANUAL:
394                                 resp.mode = NETWORK_SELECT_MODE_GSM_MANUAL;
395                         break;
396                 }
397         }
398         else {
399                 err("RESPONSE NOK");
400         }
401         ReleaseResponse();
402
403         dbg("resp.mode = %d", resp.mode);
404         ur = tcore_pending_ref_user_request(pending);
405         if (ur) {
406                 tcore_user_request_send_response(ur, TRESP_NETWORK_GET_PLMN_SELECTION_MODE, sizeof(struct tresp_network_get_plmn_selection_mode), &resp);
407         }
408 }
409
410 static void on_response_search_network(TcorePending *pending, int data_len, const void *data, void *user_data)
411 {
412         UserRequest *ur;
413         struct tresp_network_search resp;
414         int i = 0, ret=0;
415         char* line=NULL;
416
417         memset(&resp, 0, sizeof(struct tresp_network_search));
418
419         if (sp_response->success > 0) {
420                 dbg("RESPONSE OK");
421                 line = sp_response->p_intermediates->line;
422                 ret = at_tok_start(&line);
423                 if (ret < 0)
424                         AT_TOK_ERROR(line);
425                 while(at_tok_hasmore(&line))
426                 {
427                 /*
428                  *      +COPS: [list of supported (<stat>,long alphanumeric <oper>,short alphanumeric <oper>,numeric <oper>[,<AcT>])s]
429                  *             [,,(list of supported <mode>s),(list of supported <format>s)]
430                  */
431                         int stat=0, AcT=0;
432                         char* oper=NULL, *p;
433                         int commas = 0;
434
435                         dbg("line0 %s", line);
436                         at_tok_skip_bracket(&line);
437                         for (p = line ; *p != ')' ;p++) {
438                                 if (*p == ',')
439                                         commas++;
440                         }
441
442                         /* <stat>: integer type */
443                         ret = at_tok_nextint(&line,&stat);
444                         if (ret < 0)
445                                 AT_TOK_ERROR(line);
446
447                         /* long alphanumeric <oper> */
448                         ret = at_tok_nextstr(&line,&oper);
449                         if (ret < 0)
450                                 AT_TOK_ERROR(line);
451
452                         /* short alphanumeric <oper> */
453                         ret = at_tok_nextstr(&line,&oper);
454                         if (ret < 0)
455                                 AT_TOK_ERROR(line);
456
457                         /* numeric <oper> */
458                         /* [NOTICE] struct "tresp_network_search" only supports numeric type */
459                         ret = at_tok_nextstr(&line,&oper);
460                         if (ret < 0)
461                                 AT_TOK_ERROR(line);
462
463                         if (commas == 4) {
464                                 /* [,<AcT>]: integer type; access technology selected */
465                                 ret = at_tok_nextint(&line,&AcT);
466                                 if (ret < 0)
467                                         AT_TOK_ERROR(line);
468                         }
469
470                         dbg("mode = %d, oper=%s, AcT=%d", stat, oper?oper:"null", AcT);
471                         resp.list[i].status = stat;
472                         resp.list[i].act = lookup_tbl_access_technology[AcT];
473                         memcpy(resp.list[i].plmn, oper, 6);
474                         if (resp.list[i].plmn[5] == '#')
475                                 resp.list[i].plmn[5] = '\0';
476
477                         dbg("resp.list[%d].act = 0x%x, resp.list[%d].plmn=%s", i, resp.list[i].act, i, resp.list[i].plmn);
478                         i++;
479                 }
480                 resp.list_count = i;
481                 dbg("resp.list_count=%d", resp.list_count);
482                 ur = tcore_pending_ref_user_request(pending);
483                 if (ur) {
484                         tcore_user_request_send_response(ur, TRESP_NETWORK_SEARCH, sizeof(struct tresp_network_search), &resp);
485                 }
486
487         }
488         else {
489                 err("RESPONSE NOK");
490         }
491         ReleaseResponse();
492 }
493
494 static void on_response_get_serving_network(TcorePending *pending, int data_len, const void *data, void *user_data)
495 {
496         UserRequest *ur;
497         struct tresp_network_get_serving_network resp;
498         CoreObject *o;
499         char plmn[7];
500         enum telephony_network_access_technology act = NETWORK_ACT_UNKNOWN;
501         int ret;
502
503         /* AT parsing variable */
504         char* line=NULL;
505         int mode=0, format=0, AcT=0;
506         char* oper=NULL;
507
508         if (sp_response->success > 0) {
509                 dbg("RESPONSE OK");
510                 line = sp_response->p_intermediates->line;
511                 ret = at_tok_start(&line);
512                 if (ret < 0)
513                         AT_TOK_ERROR(line);
514
515                 ret = at_tok_nextint(&line,&mode);
516                 if (ret < 0)
517                         AT_TOK_ERROR(line);
518
519                 ret = at_tok_nextint(&line,&format);
520                 if (ret < 0)
521                         AT_TOK_ERROR(line);
522
523                 ret = at_tok_nextstr(&line,&oper);
524                 if (ret < 0)
525                         AT_TOK_ERROR(line);
526
527                 ret = at_tok_nextint(&line,&AcT);
528                 if (ret < 0)
529                         AT_TOK_ERROR(line);
530
531                 dbg("mode = %d, format=%d, oper=%s, AcT=%d\n", mode, format, oper, AcT);
532
533                 memset(plmn, 0, 7);
534                 memcpy(plmn, oper, 6);
535                 if (plmn[5] == '#')
536                         plmn[5] = '\0';
537
538                 o = tcore_pending_ref_core_object(pending);
539
540                 tcore_network_set_plmn(o, plmn);
541                 tcore_network_get_access_technology(o, &act);
542                 dbg("prev_act = 0x%x, new_act = 0x%x", act,lookup_tbl_access_technology[AcT]);
543                 act = lookup_tbl_access_technology[AcT];
544                 tcore_network_set_access_technology(o, act);
545
546                 if (_is_cdma(act) == FALSE) {
547                         tcore_network_set_lac(o, current_lac);
548                 }
549
550                 memcpy(resp.plmn, plmn, 6);
551                 resp.act = act;
552                 resp.gsm.lac = current_lac;
553                 ur = tcore_pending_ref_user_request(pending);
554                 if (ur) {
555                         tcore_user_request_send_response(ur, TRESP_NETWORK_GET_SERVING_NETWORK, sizeof(struct tresp_network_get_serving_network), &resp);
556                 }
557                 else {
558                         struct tnoti_network_change network_change;
559
560                         memset(&network_change, 0, sizeof(struct tnoti_network_change));
561                         memcpy(network_change.plmn, plmn, 6);
562
563                         network_change.act = act;
564                         network_change.gsm.lac = current_lac;
565
566                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_pending_ref_plugin(pending)), tcore_pending_ref_core_object(pending),
567                                         TNOTI_NETWORK_CHANGE, sizeof(struct tnoti_network_change), &network_change);
568                 }
569         }
570         else {
571                 err("RESPONSE NOK");
572         }
573         ReleaseResponse();
574         return;
575 }
576
577 static gboolean on_event_network_regist(CoreObject *o, const void *event_info, void *user_data)
578 {
579         struct tnoti_network_registration_status regist_status;
580         enum telephony_network_service_domain_status cs_status;
581         enum telephony_network_service_domain_status ps_status;
582         enum telephony_network_service_type service_type;
583         enum telephony_network_access_technology act = NETWORK_ACT_UNKNOWN;
584
585         char *line = (char *)event_info;
586         int ret;
587         unsigned char svc_domain;
588         int stat=0, AcT=0;
589         unsigned int lac=0, ci=0, rac=0;
590
591         dbg("NOTI RECEIVED");
592
593         /* CS domain */
594         if (strStartsWith(line,"+CREG:"))
595                 svc_domain = NETWORK_SERVICE_DOMAIN_CS;
596         /* PS domain */
597         else if (strStartsWith(line,"+CGREG:"))
598                 svc_domain = NETWORK_SERVICE_DOMAIN_PS;
599         else
600                 return TRUE;
601
602         dbg("svc_domain = 0x%x", svc_domain);
603
604         ret = at_tok_start(&line);
605         if (ret < 0)
606                 AT_NOTI_TOK_ERROR(line);
607
608         ret = at_tok_nextint(&line, &stat);
609         if (ret < 0)
610                 goto process;
611
612         ret = at_tok_nexthexint(&line, (int *)&lac);
613         if (ret < 0)
614                 goto process;
615         else {
616                 dbg("Found lac=0x%x",lac);
617                 /* <stat> 1 : registered, home network */
618                 /*        5 : registered, roaming      */
619                 if ( stat==1 || stat==5 )
620                         current_lac = lac;
621         }
622
623         ret = at_tok_nexthexint(&line, (int *)&ci);
624         if (ret < 0)
625                 goto process;
626         else
627                 dbg("Found ci=0x%x", ci);
628
629         ret = at_tok_nextint(&line, (int *)&AcT);
630         if (ret < 0)
631                 goto process;
632
633         if (svc_domain == NETWORK_SERVICE_DOMAIN_PS) {
634                 ret = at_tok_nexthexint(&line, (int *)&rac);
635                 if (ret < 0)
636                         goto process;
637                 else
638                         dbg("Found rac=0x%x", rac);
639         }
640         /*
641          *      <lac>: string type; two byte location area code or tracking area code in hexadecimal format
642          *      <tac>: string type; two byte tracking area code in hexadecimal format (for +CEREG:)
643          *      <ci>:  string type; four byte GERAN/UTRAN/E-UTRAN cell ID in hexadecimal format
644          *  <rac>: string type; one byte routing area code in hexadecimal format
645         */
646
647 process:
648         dbg("stat=%d, lac=0x%lx, ci=0x%lx, Act=%d, rac=0x%lx", stat, lac, ci, AcT, rac);
649
650         switch (svc_domain) {
651                 case NETWORK_SERVICE_DOMAIN_CS:
652                         cs_status = lookup_tbl_net_status[stat];
653                         tcore_network_set_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT, cs_status);
654                         break;
655
656                 case NETWORK_SERVICE_DOMAIN_PS:
657                         ps_status = lookup_tbl_net_status[stat];
658                         tcore_network_set_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET, ps_status);
659
660                         _ps_set(tcore_object_ref_plugin(o), ps_status);
661                         break;
662         }
663
664         tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT, &cs_status);
665         tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET, &ps_status);
666
667         act = lookup_tbl_access_technology[AcT];
668         tcore_network_set_access_technology(o, act);
669
670         if (stat == AT_CREG_STAT_REG_ROAM)
671                 tcore_network_set_roaming_state(o, TRUE);
672         else
673                 tcore_network_set_roaming_state(o, FALSE);
674
675         tcore_network_get_service_type(o, &service_type);
676         dbg("prev_service_type = 0x%x", service_type);
677         service_type = _get_service_type(service_type, svc_domain, act, cs_status, ps_status);
678         dbg("new_service_type = 0x%x", service_type);
679         tcore_network_set_service_type(o, service_type);
680
681         tcore_network_set_lac(o, lac);
682         tcore_network_set_rac(o, rac);
683         tcore_network_set_cell_id(o, ci);
684
685         if (_is_cdma(act) == FALSE) {
686                 struct tnoti_network_location_cellinfo net_lac_cell_info;
687                 net_lac_cell_info.lac = lac;
688                 net_lac_cell_info.cell_id = ci;
689
690                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_LOCATION_CELLINFO,
691                                 sizeof(struct tnoti_network_location_cellinfo), &net_lac_cell_info);
692         }
693
694         regist_status.cs_domain_status = cs_status;
695         regist_status.ps_domain_status = ps_status;
696         regist_status.service_type = service_type;
697         regist_status.roaming_status = tcore_network_get_roaming_state(o);
698
699         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
700                         TNOTI_NETWORK_REGISTRATION_STATUS, sizeof(struct tnoti_network_registration_status), &regist_status);
701
702         get_serving_network(o, NULL);
703
704         return TRUE;
705 }
706
707 static gboolean on_event_network_icon_info(CoreObject *o, const void *event_info, void *user_data)
708 {
709         char *line = (char *)event_info;
710         static struct tnoti_network_icon_info net_icon_info = {0xff,0,0,0};
711         int ret;
712         int descr=0, ind=0;
713
714 #define CIND_NOTI_RSSI          10
715 #define CIND_NOTI_BATTERY       15
716
717         ret = at_tok_start(&line);
718         if (ret < 0)
719                 AT_NOTI_TOK_ERROR(line);
720
721         ret = at_tok_nextint(&line, &descr);
722         if (ret < 0)
723                 AT_NOTI_TOK_ERROR(line);
724
725         ret = at_tok_nextint(&line, &ind);
726         if (ret < 0)
727                 AT_NOTI_TOK_ERROR(line);
728
729         switch(descr) {
730                 case CIND_NOTI_RSSI:
731                         dbg("CIND_NOTI_RSSI. ind=%d",ind);
732                         net_icon_info.rssi = ind;
733                         break;
734                 case CIND_NOTI_BATTERY:
735                         dbg("CIND_NOTI_BATTERY. ind=%d",ind);
736                         net_icon_info.battery = ind;
737                         break;
738
739                 default:
740                         err("This event is not handled val=%d",descr);
741                         return TRUE;
742         }
743
744         dbg("type=%d, rssi=%d, battery=%d, hdr_rssi=%d",
745                         net_icon_info.type, net_icon_info.rssi, net_icon_info.battery, net_icon_info.hdr_rssi);
746
747         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_NETWORK_ICON_INFO,
748                         sizeof(struct tnoti_network_icon_info), &net_icon_info);
749
750         return TRUE;
751 }
752
753 static void on_sim_resp_hook_get_netname(UserRequest *ur, enum tcore_response_command command, unsigned int data_len,
754                 const void *data, void *user_data)
755 {
756         const struct tresp_sim_read *resp = data;
757         CoreObject *o = user_data;
758         struct tnoti_network_registration_status regist_status;
759
760         if (command == TRESP_SIM_GET_SPN) {
761                 dbg("OK SPN GETTING!!");
762                 dbg("resp->result = 0x%x", resp->result);
763                 dbg("resp->data.spn.display_condition = 0x%x", resp->data.spn.display_condition);
764                 dbg("resp->data.spn.spn = [%s]", resp->data.spn.spn);
765
766                 tcore_network_set_network_name(o, TCORE_NETWORK_NAME_TYPE_SPN, (const char *)resp->data.spn.spn);
767
768                 /**
769                  * display condition
770                  *  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
771                  *          1 = display of registered PLMN name required when registered PLMN is either HPLMN or a PLMN in the service provider PLMN list
772                  *  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
773                  *          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
774                  */
775                 if (resp->data.spn.display_condition & 0x01) {
776                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_NETWORK);
777                 }
778                 if ((resp->data.spn.display_condition & 0x02) == 0) {
779                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_SPN);
780                 }
781                 if ((resp->data.spn.display_condition & 0x03) == 0x01) {
782                         tcore_network_set_network_name_priority(o, TCORE_NETWORK_NAME_PRIORITY_ANY);
783                 }
784         }
785
786         tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT, &regist_status.cs_domain_status);
787         tcore_network_get_service_status(o, TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET, &regist_status.ps_domain_status);
788         tcore_network_get_service_type(o, &regist_status.service_type);
789         regist_status.roaming_status = tcore_network_get_roaming_state(o);
790
791         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
792                         TNOTI_NETWORK_REGISTRATION_STATUS, sizeof(struct tnoti_network_registration_status), &regist_status);
793 }
794
795 static enum tcore_hook_return on_hook_sim_init(Server *s, CoreObject *source, enum tcore_notification_command command,
796                 unsigned int data_len, void *data, void *user_data)
797 {
798         const struct tnoti_sim_status *sim = data;
799         UserRequest *ur = NULL;
800
801         if (sim->sim_status == SIM_STATUS_INIT_COMPLETED) {
802                 ur = tcore_user_request_new(NULL, NULL);
803                 tcore_user_request_set_command(ur, TREQ_SIM_GET_SPN);
804                 tcore_user_request_set_response_hook(ur, on_sim_resp_hook_get_netname, user_data);
805                 tcore_object_dispatch_request(source, ur);
806         }
807
808         return TCORE_HOOK_RETURN_CONTINUE;
809 }
810
811 static TReturn search_network(CoreObject *o, UserRequest *ur)
812 {
813         /* AT command variable*/
814         struct ATReqMetaInfo metainfo;
815         char* atcmd = NULL;
816
817         if (!o || !ur)
818                 return TCORE_RETURN_EINVAL;
819
820         __set_metainfo(ur, &metainfo, SINGLELINE,"+COPS:");
821
822         atcmd = g_strdup("AT+COPS=?\r");
823         dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",atcmd, "N/A", strlen(atcmd));
824
825         __send_at_request(o, atcmd, ur, on_response_search_network);
826         free(atcmd);
827
828         return TCORE_RETURN_SUCCESS;
829 }
830
831 static TReturn set_plmn_selection_mode(CoreObject *o, UserRequest *ur)
832 {
833         const struct treq_network_set_plmn_selection_mode *req_data;
834
835         /* AT command variable*/
836         struct ATReqMetaInfo metainfo;
837         char* atcmd = NULL;
838         char plmn[7];
839
840         if (!o || !ur)
841                 return TCORE_RETURN_EINVAL;
842
843         req_data = tcore_user_request_ref_data(ur, NULL);
844         __set_metainfo(ur, &metainfo, NO_RESULT, NULL);
845
846         if (req_data->mode != NETWORK_SELECT_MODE_GSM_MANUAL) {
847                 /* AT_COPS_MODE_AUTOMATIC 0*/
848                 atcmd = g_strdup("AT+COPS=0\r");
849         }
850         else {
851                 memset(plmn, 0, 7);
852                 memcpy(plmn, req_data->plmn, 6);
853
854                 if (strlen(req_data->plmn) == 5) {
855                         plmn[5] = '#';
856                 }
857                 /* AT_COPS_MODE_MANUAL 1*/
858                 /* AT_COPS_FORMAT_NUMERIC 2*/
859                 atcmd = g_strdup_printf("AT+COPS=0%s\r", plmn);
860         }
861         dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",atcmd, "N/A", strlen(atcmd));
862
863         __send_at_request(o, atcmd, ur, on_response_set_plmn_selection_mode);
864         free(atcmd);
865
866         return TCORE_RETURN_SUCCESS;
867 }
868
869
870 static TReturn get_plmn_selection_mode(CoreObject *o, UserRequest *ur)
871 {
872         /* AT command variable*/
873         struct ATReqMetaInfo metainfo;
874         char* atcmd = NULL;
875
876         if (!o || !ur)
877                 return TCORE_RETURN_EINVAL;
878
879         __set_metainfo(ur, &metainfo, SINGLELINE,"+COPS:");
880
881         atcmd = g_strdup("AT+COPS?\r");
882         dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",atcmd, "N/A", strlen(atcmd));
883
884         __send_at_request(o, atcmd, ur, on_response_get_plmn_selection_mode);
885         free(atcmd);
886
887         return TCORE_RETURN_SUCCESS;
888 }
889
890 static TReturn set_service_domain(CoreObject *o, UserRequest *ur)
891 {
892         dbg("set_service_domain is not supported!");
893         return TCORE_RETURN_SUCCESS;
894 }
895
896 static TReturn get_service_domain(CoreObject *o, UserRequest *ur)
897 {
898         dbg("get_service_domain is not supported!");
899         return TCORE_RETURN_SUCCESS;
900 }
901
902 static TReturn set_band(CoreObject *o, UserRequest *ur)
903 {
904         dbg("set_band is not supported!");
905         return TCORE_RETURN_SUCCESS;
906 }
907
908 static TReturn get_band(CoreObject *o, UserRequest *ur)
909 {
910         dbg("get_band is not supported!");
911         return TCORE_RETURN_SUCCESS;
912 }
913
914 static TReturn set_preferred_plmn(CoreObject *o, UserRequest *ur)
915 {
916         dbg("set_preferred_plmn is not supported!");
917         return TCORE_RETURN_SUCCESS;
918 }
919
920 static TReturn get_preferred_plmn(CoreObject *o, UserRequest *ur)
921 {
922         dbg("get_preferred_plmn is not supported!");
923         return TCORE_RETURN_SUCCESS;
924 }
925
926 static TReturn set_order(CoreObject *o, UserRequest *ur)
927 {
928         dbg("set_order is not supported!");
929         return TCORE_RETURN_SUCCESS;
930 }
931
932 static TReturn get_order(CoreObject *o, UserRequest *ur)
933 {
934         dbg("get_order is not supported!");
935         return TCORE_RETURN_SUCCESS;
936 }
937
938 static TReturn set_power_on_attach(CoreObject *o, UserRequest *ur)
939 {
940         dbg("set_power_on_attach is not supported!");
941         return TCORE_RETURN_SUCCESS;
942 }
943
944 static TReturn get_power_on_attach(CoreObject *o, UserRequest *ur)
945 {
946         dbg("get_power_on_attach is not supported!");
947         return TCORE_RETURN_SUCCESS;
948 }
949
950 static TReturn set_cancel_manual_search(CoreObject *o, UserRequest *ur)
951 {
952         dbg("set_cancel_manual_search is not supported!");
953         return TCORE_RETURN_SUCCESS;
954 }
955
956 static TReturn get_serving_network(CoreObject *o, UserRequest *ur)
957 {
958         /* AT command variable*/
959         struct ATReqMetaInfo metainfo;
960         char* atcmd = NULL;
961
962         if (!o)
963                 return TCORE_RETURN_EINVAL;
964
965         if (!ur)
966                 ur = tcore_user_request_new(NULL, NULL);
967
968         __set_metainfo(ur, &metainfo, SINGLELINE,"+COPS:");
969
970         atcmd = g_strdup("AT+COPS?\r");
971         dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",atcmd, "N/A", strlen(atcmd));
972
973         __send_at_request(o, atcmd, ur, on_response_get_serving_network);
974         free(atcmd);
975         return TCORE_RETURN_SUCCESS;
976 }
977
978
979
980 static struct tcore_network_operations network_ops = {
981         .search = search_network,
982         .set_plmn_selection_mode = set_plmn_selection_mode,
983         .get_plmn_selection_mode = get_plmn_selection_mode,
984         .set_service_domain = set_service_domain,
985         .get_service_domain = get_service_domain,
986         .set_band = set_band,
987         .get_band = get_band,
988         .set_preferred_plmn = set_preferred_plmn,
989         .get_preferred_plmn = get_preferred_plmn,
990         .set_order = set_order,
991         .get_order = get_order,
992         .set_power_on_attach = set_power_on_attach,
993         .get_power_on_attach = get_power_on_attach,
994         .set_cancel_manual_search = set_cancel_manual_search,
995         .get_serving_network = get_serving_network,
996 };
997
998 gboolean s_network_init(TcorePlugin *plugin, TcoreHal *h)
999 {
1000         CoreObject *o;
1001
1002         o = tcore_network_new(plugin, "umts_network", &network_ops, h);
1003         if (!o)
1004                 return FALSE;
1005
1006         tcore_object_add_callback(o, EVENT_NETWORK_REGISTRATION, on_event_network_regist, NULL);
1007         tcore_object_add_callback(o, EVENT_NETWORK_ICON_INFO, on_event_network_icon_info, NULL);
1008
1009         tcore_server_add_notification_hook(tcore_plugin_ref_server(plugin), TNOTI_SIM_STATUS, on_hook_sim_init, o);
1010
1011         _insert_mcc_mnc_oper_list(plugin, o);
1012
1013         return TRUE;
1014 }
1015
1016 void s_network_exit(TcorePlugin *plugin)
1017 {
1018         CoreObject *o;
1019
1020         o = tcore_plugin_ref_core_object(plugin, "umts_network");
1021
1022         tcore_network_free(o);
1023 }