63e7f6e33efe4759559025bb88f938c26ab238af
[platform/upstream/connman.git] / plugins / telephony.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2011-2013  Samsung Electronics Co., Ltd. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdlib.h>
29
30 #include <gdbus.h>
31 #include <string.h>
32
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/plugin.h>
35 #include <connman/device.h>
36 #include <connman/network.h>
37 #include <connman/ipconfig.h>
38 #include <connman/dbus.h>
39 #include <connman/inet.h>
40 #include <connman/technology.h>
41 #include <connman/log.h>
42
43 #define PS_DBUS_SERVICE                         "com.tcore.ps"
44
45 #define PS_MASTER_INTERFACE             PS_DBUS_SERVICE ".master"
46 #define PS_MODEM_INTERFACE              PS_DBUS_SERVICE ".modem"
47 #define PS_SERVICE_INTERFACE            PS_DBUS_SERVICE ".service"
48 #define PS_CONTEXT_INTERFACE            PS_DBUS_SERVICE ".context"
49
50 /* methods */
51 #define GET_MODEMS                      "GetModems"
52 #define GET_SERVICES                    "GetServices"
53 #define GET_CONTEXTS                    "GetContexts"
54 #define ACTIVATE_CONTEXT                "Activate"
55 #define DEACTIVATE_CONTEXT              "Deactivate"
56 #define GET_PROPERTIES                  "GetProperties"
57 #define SET_PROPERTY                    "SetProperties"
58
59 /* signals */
60 #define MODEM_ADDED                     "ModemAdded"
61 #define MODEM_REMOVED                   "ModemRemoved"
62 #define SERVICE_ADDED                   "ServiceAdded"
63 #define SERVICE_REMOVED                 "ServiceRemoved"
64 #define CONTEXT_ADDED                   "ContextAdded"
65 #define CONTEXT_REMOVED                 "ContextRemoved"
66 #define PROPERTY_CHANGED                "PropertyChanged"
67
68 #define TIMEOUT 40000
69
70 #define STRING2BOOL(a)  ((g_str_equal(a, "TRUE")) ?  (TRUE):(FALSE))
71
72 static DBusConnection *connection;
73 static GHashTable       *modem_hash;
74 static GHashTable       *service_hash;
75 static GHashTable       *network_hash;
76
77 struct telephony_service {
78         char *path;
79
80         gpointer p_modem;
81         char *act;
82         gboolean roaming; /* global roaming state */
83         gboolean ps_attached; /* packet service is available */
84 };
85
86 struct telephony_modem {
87         char *path;
88
89         char *operator;
90         gboolean powered;
91         gboolean sim_init;
92         gboolean flight_mode;
93         gboolean data_allowed;
94         gboolean roaming_allowed;
95
96         struct connman_device *device;
97         struct telephony_service *s_service;
98 };
99
100 struct telephony_network {
101         char *path;
102         struct connman_network *network;
103
104         enum connman_ipconfig_method ipv4_method;
105         struct connman_ipaddress *ipv4_address;
106
107         enum connman_ipconfig_method ipv6_method;
108         struct connman_ipaddress *ipv6_address;
109 };
110
111 /* function prototype */
112 static void telephony_connect(DBusConnection *connection, void *user_data);
113 static void telephony_disconnect(DBusConnection *connection, void *user_data);
114 static void __remove_modem(gpointer data);
115 static void __remove_service(gpointer data);
116 static void __remove_network(gpointer data);
117
118 static int __modem_probe(struct connman_device *device);
119 static void __modem_remove(struct connman_device *device);
120 static int __modem_enable(struct connman_device *device);
121 static int __modem_disable(struct connman_device *device);
122
123 static int __network_probe(struct connman_network *network);
124 static void __network_remove(struct connman_network *network);
125 static int __network_connect(struct connman_network *network);
126 static int __network_disconnect(struct connman_network *network);
127
128
129 /* dbus request and reply */
130 static int __dbus_request(const char *path, const char *interface,
131                         const char *method,
132                         DBusPendingCallNotifyFunction notify, void *user_data,
133                         DBusFreeFunction free_function, int type, ...);
134
135 static int __request_get_modems(void);
136 static void __response_get_modems(DBusPendingCall *call, void *user_data);
137 static int __request_get_services(const char *path);
138 static void __response_get_services(DBusPendingCall *call, void *user_data);
139 static int __request_get_contexts(struct telephony_modem *modem);
140 static void __response_get_contexts(DBusPendingCall *call, void *user_data);
141 static int __request_network_activate(struct connman_network *network);
142 static void __response_network_activate(DBusPendingCall *call, void *user_data);
143 static int __request_network_deactivate(struct connman_network *network);
144
145 /* telephony internal function */
146 static void __add_modem(const char *path, DBusMessageIter *prop);
147 static void __add_service(struct telephony_modem *modem,
148                         const char *service_path, DBusMessageIter *prop);
149 static void __add_connman_device(const char *modem_path, const char *operator);
150 static void __remove_connman_device(struct telephony_modem *modem);
151 static void __remove_connman_networks(struct connman_device *device);
152 static void __set_device_powered(struct telephony_modem *modem,
153                                         gboolean powered);
154 static int __check_device_powered(const char *path, gboolean online);
155 static gboolean __check_network_available(struct connman_network *network);
156 static void __create_service(struct connman_network *network);
157 static int __add_context(struct connman_device *device, const char *path,
158                                                         DBusMessageIter *prop);
159 static gboolean __set_network_ipconfig(struct telephony_network *network,
160                                                         DBusMessageIter *dict);
161 static void __set_network_connected(struct telephony_network *network,
162                                                         gboolean connected);
163 static char *__get_ident(const char *path);
164
165 /* signal handler */
166 static gboolean __changed_modem(DBusConnection *connection,
167                                 DBusMessage *message, void *user_data);
168 static gboolean __added_modem(DBusConnection *connection,
169                                 DBusMessage *message, void *user_data);
170 static gboolean __removed_modem(DBusConnection *connection,
171                                 DBusMessage *message, void *user_data);
172 static gboolean __changed_service(DBusConnection *connection,
173                                 DBusMessage *message, void *user_data);
174 static gboolean __added_service(DBusConnection *connection,
175                                 DBusMessage *message, void *user_data);
176 static gboolean __removed_service(DBusConnection *connection,
177                                 DBusMessage *message, void *user_data);
178 static gboolean __changed_context(DBusConnection *connection,
179                                 DBusMessage *message, void *user_data);
180 static gboolean __added_context(DBusConnection *connection,
181                                 DBusMessage *message, void *user_data);
182 static gboolean __removed_context(DBusConnection *connection,
183                                 DBusMessage *message, void *user_data);
184
185 /* device driver */
186 static struct connman_device_driver modem_driver = {
187         .name           = "device",
188         .type           = CONNMAN_DEVICE_TYPE_CELLULAR,
189         .probe          = __modem_probe,
190         .remove         = __modem_remove,
191         .enable         = __modem_enable,
192         .disable        = __modem_disable,
193 };
194
195 /* network driver */
196 static struct connman_network_driver network_driver = {
197         .name           = "network",
198         .type           = CONNMAN_NETWORK_TYPE_CELLULAR,
199         .probe          = __network_probe,
200         .remove         = __network_remove,
201         .connect        = __network_connect,
202         .disconnect     = __network_disconnect,
203 };
204
205 static int tech_probe(struct connman_technology *technology)
206 {
207         return 0;
208 }
209
210 static void tech_remove(struct connman_technology *technology)
211 {
212 }
213
214 static struct connman_technology_driver tech_driver = {
215         .name           = "cellular",
216         .type           = CONNMAN_SERVICE_TYPE_CELLULAR,
217         .probe          = tech_probe,
218         .remove         = tech_remove,
219 };
220
221 /* local function */
222 static void telephony_connect(DBusConnection *connection, void *user_data)
223 {
224         DBG("connection %p", connection);
225         modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
226                                                 g_free, __remove_modem);
227         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
228                                                 g_free, __remove_service);
229         network_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
230                                                 g_free, __remove_network);
231         __request_get_modems();
232         return;
233 }
234
235 static void telephony_disconnect(DBusConnection *connection, void *user_data)
236 {
237         DBG("connection %p", connection);
238
239         if (modem_hash != NULL) {
240                 g_hash_table_destroy(modem_hash);
241                 modem_hash = NULL;
242         }
243
244         if (network_hash != NULL) {
245                 g_hash_table_destroy(network_hash);
246                 network_hash = NULL;
247         }
248
249         return;
250 }
251
252 static void __remove_modem(gpointer data)
253 {
254         struct telephony_modem *modem = data;
255
256         __remove_connman_device(modem);
257
258         g_free(modem->path);
259         g_free(modem->operator);
260         g_free(modem);
261 }
262
263 static void __remove_service(gpointer data)
264 {
265         struct telephony_service *service = data;
266
267         g_free(service->path);
268         g_free(service->act);
269         g_free(service);
270 }
271
272 static void __remove_network(gpointer data)
273 {
274         struct telephony_network *info = data;
275         struct connman_device *device;
276
277         device = connman_network_get_device(info->network);
278         if (device != NULL)
279                 connman_device_remove_network(device, info->network);
280
281         connman_network_unref(info->network);
282
283         g_free(info->path);
284         connman_ipaddress_free(info->ipv4_address);
285         connman_ipaddress_free(info->ipv6_address);
286         g_free(info);
287 }
288
289 static int __modem_probe(struct connman_device *device)
290 {
291         DBG("device %p", device);
292         return 0;
293 }
294
295 static void __modem_remove(struct connman_device *device)
296 {
297         DBG("device %p", device);
298 }
299
300 static int __modem_enable(struct connman_device *device)
301 {
302         const char *path = connman_device_get_string(device, "Path");
303         DBG("device %p, path, %s", device, path);
304
305         return __check_device_powered(path, TRUE);
306 }
307
308 static int __modem_disable(struct connman_device *device)
309 {
310         const char *path = connman_device_get_string(device, "Path");
311         DBG("device %p, path, %s", device, path);
312
313         return __check_device_powered(path, FALSE);
314 }
315
316 static int __network_probe(struct connman_network *network)
317 {
318         DBG("network_prove network(%p)", network);
319         return 0;
320 }
321
322 static int __network_connect(struct connman_network *network)
323 {
324         struct connman_device *device;
325         struct telephony_modem *modem;
326
327         DBG("network %p", network);
328
329         device = connman_network_get_device(network);
330         if (device == NULL)
331                 return -ENODEV;
332
333         modem = connman_device_get_data(device);
334         if (modem == NULL)
335                 return -ENODEV;
336
337         if (modem->powered == FALSE)
338                 return -ENOLINK;
339
340         return __request_network_activate(network);
341 }
342
343 static int __network_disconnect(struct connman_network *network)
344 {
345         DBG("network %p", network);
346
347         if (connman_network_get_index(network) < 0)
348                 return -ENOTCONN;
349
350         connman_network_set_associating(network, FALSE);
351
352         return __request_network_deactivate(network);
353 }
354
355 static void __network_remove(struct connman_network *network)
356 {
357         char const *path = connman_network_get_string(network, "Path");
358         DBG("network %p path %s", network, path);
359
360         g_hash_table_remove(network_hash, path);
361         return;
362 }
363
364 static int __dbus_request(const char *path, const char *interface,
365                         const char *method,
366                         DBusPendingCallNotifyFunction notify, void *user_data,
367                         DBusFreeFunction free_function, int type, ...)
368 {
369         DBusMessage *message;
370         DBusPendingCall *call;
371         dbus_bool_t ok;
372         va_list va;
373
374         DBG("Telephony request path %s %s.%s", path, interface, method);
375
376         if (path == NULL)
377                 return -EINVAL;
378
379         message = dbus_message_new_method_call(PS_DBUS_SERVICE, path,
380                                                 interface, method);
381         if (message == NULL)
382                 return -ENOMEM;
383
384         dbus_message_set_auto_start(message, FALSE);
385
386         va_start(va, type);
387         ok = dbus_message_append_args_valist(message, type, va);
388         va_end(va);
389
390         if (!ok)
391                 return -ENOMEM;
392
393         if (dbus_connection_send_with_reply(connection, message,
394                                                 &call, TIMEOUT) == FALSE) {
395                 connman_error("Failed to call %s.%s", interface, method);
396                 dbus_message_unref(message);
397                 return -EINVAL;
398         }
399
400         if (call == NULL) {
401                 connman_error("D-Bus connection not available");
402                 dbus_message_unref(message);
403                 return -EINVAL;
404         }
405
406         dbus_pending_call_set_notify(call, notify, user_data, free_function);
407
408         dbus_message_unref(message);
409
410         return -EINPROGRESS;
411 }
412
413 static int __request_get_modems(void)
414 {
415         DBG("request get modem");
416         /* call connect master */
417         return __dbus_request("/", PS_MASTER_INTERFACE, GET_MODEMS,
418                         __response_get_modems, NULL, NULL, DBUS_TYPE_INVALID);
419 }
420
421 static void __response_get_modems(DBusPendingCall *call, void *user_data)
422 {
423         DBusMessage *reply;
424         DBusError error;
425         DBusMessageIter args, dict;
426
427         DBG("");
428
429         reply = dbus_pending_call_steal_reply(call);
430
431         dbus_error_init(&error);
432
433         if (dbus_set_error_from_message(&error, reply)) {
434                 connman_error("GetModems() %s %s", error.name, error.message);
435                 dbus_error_free(&error);
436                 goto done;
437         }
438
439         DBG("message signature (%s)", dbus_message_get_signature(reply));
440
441         if (dbus_message_iter_init(reply, &args) == FALSE)
442                 goto done;
443
444         dbus_message_iter_recurse(&args, &dict);
445
446         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
447                 DBusMessageIter entry, property;
448                 const char *modem_path;
449
450                 dbus_message_iter_recurse(&dict, &entry);
451                 dbus_message_iter_get_basic(&entry, &modem_path);
452                 DBG("modem path (%s)", modem_path);
453
454                 dbus_message_iter_next(&entry);
455                 dbus_message_iter_recurse(&entry, &property);
456
457                 __add_modem(modem_path, &property);
458
459                 dbus_message_iter_next(&dict);
460         }
461
462 done:
463         dbus_message_unref(reply);
464         dbus_pending_call_unref(call);
465         return;
466 }
467
468 static int __request_get_services(const char *path)
469 {
470         DBG("request get service");
471         return __dbus_request(path, PS_MODEM_INTERFACE, GET_SERVICES,
472                                 __response_get_services, g_strdup(path),
473                                 g_free, DBUS_TYPE_INVALID);
474 }
475
476 static void __response_get_services(DBusPendingCall *call, void *user_data)
477 {
478         DBusMessage *reply;
479         DBusError error;
480         DBusMessageIter args, dict;
481
482         const char *path = user_data;
483         struct telephony_modem *modem;
484
485         modem = g_hash_table_lookup(modem_hash, path);
486         if (modem == NULL)
487                 return;
488         if (modem->device == NULL)
489                 return;
490
491         DBG("");
492
493         reply = dbus_pending_call_steal_reply(call);
494
495         dbus_error_init(&error);
496
497         if (dbus_set_error_from_message(&error, reply)) {
498                 connman_error("GetServices() %s %s", error.name, error.message);
499                 dbus_error_free(&error);
500                 goto done;
501         }
502
503         DBG("message signature (%s)", dbus_message_get_signature(reply));
504
505         if (dbus_message_iter_init(reply, &args) == FALSE)
506                 goto done;
507
508         dbus_message_iter_recurse(&args, &dict);
509
510         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
511                 DBusMessageIter entry, property;
512                 const char *service_path;
513
514                 dbus_message_iter_recurse(&dict, &entry);
515                 dbus_message_iter_get_basic(&entry, &service_path);
516                 DBG("service path (%s)", service_path);
517
518                 dbus_message_iter_next(&entry);
519                 dbus_message_iter_recurse(&entry, &property);
520
521                 __add_service(modem, service_path, &property);
522
523                 dbus_message_iter_next(&dict);
524         }
525
526 done:
527         dbus_message_unref(reply);
528         dbus_pending_call_unref(call);
529         return;
530 }
531
532 static int __request_get_contexts(struct telephony_modem *modem)
533 {
534         DBG("request get contexts");
535         return __dbus_request(modem->s_service->path,
536                                 PS_SERVICE_INTERFACE, GET_CONTEXTS,
537                                 __response_get_contexts, g_strdup(modem->path),
538                                 g_free, DBUS_TYPE_INVALID);
539 }
540
541 static void __response_get_contexts(DBusPendingCall *call, void *user_data)
542 {
543         DBusError error;
544         DBusMessage *reply;
545         DBusMessageIter args, dict;
546
547         const char *path = user_data;
548         struct telephony_modem *modem;
549
550         DBG("");
551
552         modem = g_hash_table_lookup(modem_hash, path);
553         if (modem == NULL)
554                 return;
555         if (modem->s_service == NULL)
556                         return;
557         if (modem->device == NULL)
558                 return;
559
560         reply = dbus_pending_call_steal_reply(call);
561
562         dbus_error_init(&error);
563
564         if (dbus_set_error_from_message(&error, reply)) {
565                 connman_error("GetContexts() %s %s", error.name, error.message);
566                 dbus_error_free(&error);
567                 goto done;
568         }
569
570         DBG("message signature (%s)", dbus_message_get_signature(reply));
571
572         if (dbus_message_iter_init(reply, &args) == FALSE)
573                 goto done;
574
575         dbus_message_iter_recurse(&args, &dict);
576
577         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
578                 DBusMessageIter entry, property;
579                 const char *context_path;
580
581                 dbus_message_iter_recurse(&dict, &entry);
582                 dbus_message_iter_get_basic(&entry, &context_path);
583                 DBG("context path (%s)", context_path);
584
585                 dbus_message_iter_next(&entry);
586                 dbus_message_iter_recurse(&entry, &property);
587
588                 __add_context(modem->device, context_path, &property);
589
590                 dbus_message_iter_next(&dict);
591         }
592
593 done:
594         dbus_message_unref(reply);
595         dbus_pending_call_unref(call);
596         return;
597 }
598
599 static int __request_network_activate(struct connman_network *network)
600 {
601         DBG("request network activate");
602
603         const char *path = connman_network_get_string(network, "Path");
604         DBG("network %p, path %s", network, path);
605
606         return __dbus_request(path, PS_CONTEXT_INTERFACE, ACTIVATE_CONTEXT,
607                         __response_network_activate,
608                         g_strdup(path), NULL, DBUS_TYPE_INVALID);
609 }
610
611 static void __response_network_activate(DBusPendingCall *call, void *user_data)
612 {
613         DBG("network activation response");
614
615         DBusError error;
616         DBusMessage *reply;
617
618         struct telephony_network *info;
619         const char *path = user_data;
620
621         info = g_hash_table_lookup(network_hash, path);
622         reply = dbus_pending_call_steal_reply(call);
623
624         if (info == NULL)
625                 goto done;
626
627         if (!__check_network_available(info->network)) {
628                 g_hash_table_remove(network_hash, path);
629                 goto done;
630         }
631
632         dbus_error_init(&error);
633         if (dbus_set_error_from_message(&error, reply)) {
634                 connman_error("connection activate() %s %s",
635                                         error.name, error.message);
636
637                 if (connman_network_get_index(info->network) < 0)
638                         connman_network_set_error(info->network,
639                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
640
641                 dbus_error_free(&error);
642                 goto done;
643         }
644
645 done:
646         dbus_message_unref(reply);
647         dbus_pending_call_unref(call);
648         return;
649 }
650
651 static int __request_network_deactivate(struct connman_network *network)
652 {
653         DBG("request network deactivate");
654
655         const char *path = connman_network_get_string(network, "Path");
656         DBG("network %p, path %s", network, path);
657
658         return __dbus_request(path, PS_CONTEXT_INTERFACE, DEACTIVATE_CONTEXT,
659                 NULL, NULL, NULL, DBUS_TYPE_INVALID);
660 }
661
662 static void __add_modem(const char *path, DBusMessageIter *prop)
663 {
664         struct telephony_modem *modem;
665
666         modem = g_hash_table_lookup(modem_hash, path);
667         if (modem != NULL)
668                 return;
669
670         modem = (struct telephony_modem *)malloc(
671                                         sizeof(struct telephony_modem));
672         memset(modem, 0, sizeof(struct telephony_modem));
673
674         modem->path = g_strdup(path);
675         modem->device = NULL;
676         modem->s_service = NULL;
677
678         g_hash_table_insert(modem_hash, g_strdup(path), modem);
679
680         while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) {
681                 DBusMessageIter entry;
682                 const char *key, *tmp;
683
684                 dbus_message_iter_recurse(prop, &entry);
685                 dbus_message_iter_get_basic(&entry, &key);
686
687                 dbus_message_iter_next(&entry);
688                 dbus_message_iter_get_basic(&entry, &tmp);
689
690                 DBG("key (%s) value(%s)", key, tmp);
691
692                 if (g_str_equal(key, "powered") == TRUE) {
693                         modem->powered = STRING2BOOL(tmp);
694                 } else if (g_str_equal(key, "operator") == TRUE) {
695                         modem->operator = g_strdup(tmp);
696                 } else if (g_str_equal(key, "sim_init") == TRUE) {
697                         modem->sim_init = STRING2BOOL(tmp);
698                 } else if (g_str_equal(key, "flight_mode") == TRUE) {
699                         modem->flight_mode = STRING2BOOL(tmp);
700                 } else if (g_str_equal(key, "roaming_allowed") == TRUE) {
701                         modem->roaming_allowed = STRING2BOOL(tmp);
702                 } else if (g_str_equal(key, "data_allowed") == TRUE) {
703                         modem->data_allowed = STRING2BOOL(tmp);
704                 }
705                 dbus_message_iter_next(prop);
706         }
707
708         __add_connman_device(path, modem->operator);
709         __set_device_powered(modem, modem->powered);
710
711         if (modem->powered != TRUE) {
712                 DBG("modem is not powered");
713                 return;
714         }
715
716         __request_get_services(modem->path);
717
718         return;
719 }
720
721 static void __add_service(struct telephony_modem *modem,
722                                 const char *service_path, DBusMessageIter *prop)
723 {
724         struct telephony_service *service;
725
726         if (modem->s_service != NULL)
727                 return;
728
729         service = (struct telephony_service *)g_try_malloc(
730                                         sizeof(struct telephony_service));
731         if (service == NULL)
732                 return;
733
734         memset(service, 0, sizeof(struct telephony_service));
735
736         service->path = g_strdup(service_path);
737         service->p_modem = modem;
738         g_hash_table_insert(service_hash, g_strdup(service_path), service);
739
740         while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) {
741                 DBusMessageIter entry;
742                 const char *key, *tmp;
743
744                 dbus_message_iter_recurse(prop, &entry);
745                 dbus_message_iter_get_basic(&entry, &key);
746
747                 dbus_message_iter_next(&entry);
748                 dbus_message_iter_get_basic(&entry, &tmp);
749
750                 DBG("key (%s) value(%s)", key, tmp);
751
752                 if (g_str_equal(key, "roaming") == TRUE) {
753                         service->roaming = STRING2BOOL(tmp);
754                 } else if (g_str_equal(key, "act") == TRUE) {
755                         service->act = g_strdup(tmp);
756                 } else if (g_str_equal(key, "ps_attached") == TRUE) {
757                         service->ps_attached = STRING2BOOL(tmp);
758                 }
759
760                 dbus_message_iter_next(prop);
761         }
762
763         modem->s_service = service;
764         __request_get_contexts(modem);
765
766         return;
767 }
768
769 static void __add_connman_device(const char *modem_path, const char *operator)
770 {
771         struct telephony_modem *modem;
772         struct connman_device *device;
773
774         DBG("path %s operator %s", modem_path, operator);
775
776         if (modem_path == NULL)
777                 return;
778
779         if (operator == NULL)
780                 return;
781
782         modem = g_hash_table_lookup(modem_hash, modem_path);
783         if (modem == NULL)
784                 return;
785
786         if (modem->device) {
787                 if (!g_strcmp0(operator,
788                                 connman_device_get_ident(modem->device)))
789                         return;
790
791                 __remove_connman_device(modem);
792         }
793
794         if (strlen(operator) == 0)
795                 return;
796
797         device = connman_device_create(operator, CONNMAN_DEVICE_TYPE_CELLULAR);
798         if (device == NULL)
799                 return;
800
801         connman_device_set_ident(device, operator);
802         connman_device_set_string(device, "Path", modem_path);
803         connman_device_set_data(device, modem);
804
805         if (connman_device_register(device) < 0) {
806                 connman_error("Failed to register cellular device");
807                 connman_device_unref(device);
808                 return;
809         }
810
811         modem->device = device;
812
813         return;
814 }
815
816 static void __remove_connman_device(struct telephony_modem *modem)
817 {
818         DBG("modem %p path %s device %p", modem, modem->path, modem->device);
819
820         if (modem->device == NULL)
821                 return;
822
823         __remove_connman_networks(modem->device);
824
825         connman_device_unregister(modem->device);
826         connman_device_unref(modem->device);
827
828         modem->device = NULL;
829
830         return;
831 }
832
833 static void __remove_connman_networks(struct connman_device *device)
834 {
835         GHashTableIter iter;
836         gpointer key, value;
837         GSList *info_list = NULL;
838         GSList *list;
839
840         if (network_hash == NULL)
841                 return;
842
843         g_hash_table_iter_init(&iter, network_hash);
844
845         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
846                 struct telephony_network *info = value;
847
848                 if (connman_network_get_device(info->network) != device)
849                         continue;
850
851                 info_list = g_slist_append(info_list, info);
852         }
853
854         for (list = info_list; list != NULL; list = list->next) {
855                 struct telephony_network *info = list->data;
856                 connman_device_remove_network(device, info->network);
857         }
858
859         g_slist_free(info_list);
860 }
861
862 static void __set_device_powered(struct telephony_modem *modem,
863                                         gboolean powered)
864 {
865         DBG("set modem(%s) powered(%d)", modem->path, powered);
866
867         if (modem->device)
868                 connman_device_set_powered(modem->device, powered);
869
870         return;
871 }
872
873 static int __check_device_powered(const char *path, gboolean powered)
874 {
875         struct telephony_modem *modem = g_hash_table_lookup(modem_hash, path);
876
877         if (modem == NULL)
878                 return -ENODEV;
879
880         DBG("check modem (%s) powered (%d)", modem->path, modem->powered);
881
882         if (modem->powered == powered)
883                 return -EALREADY;
884
885         return 0;
886 }
887
888 static gboolean __check_network_available(struct connman_network *network)
889 {
890         if (network == NULL || connman_network_get_device(network) == NULL) {
891                 DBG("Modem or network was removed");
892                 return FALSE;
893         }
894
895         return TRUE;
896 }
897
898 static int __add_context(struct connman_device *device, const char *path,
899                                 DBusMessageIter *prop)
900 {
901         char *ident;
902         gboolean active = FALSE;
903
904         struct telephony_modem *modem = connman_device_get_data(device);
905         struct connman_network *network;
906         struct telephony_network *info;
907
908         DBG("modem %p device %p path %s", modem, device, path);
909
910         ident = __get_ident(path);
911
912         network = connman_device_get_network(device, ident);
913         if (network != NULL)
914                 return -EALREADY;
915
916         info = g_hash_table_lookup(network_hash, path);
917         if (info != NULL) {
918                 DBG("path %p already exists with device %p", path,
919                         connman_network_get_device(info->network));
920
921                 if (connman_network_get_device(info->network))
922                         return -EALREADY;
923
924                 g_hash_table_remove(network_hash, path);
925         }
926
927         network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
928         if (network == NULL)
929                 return -ENOMEM;
930
931         info = (struct telephony_network *)g_try_malloc(
932                                         sizeof(struct telephony_network));
933         if (info == NULL) {
934                 connman_network_unref(network);
935                 return -ENOMEM;
936         }
937
938         memset(info, 0, sizeof(struct telephony_network));
939
940         info->path = g_strdup(path);
941
942         connman_ipaddress_clear(info->ipv4_address);
943         connman_ipaddress_clear(info->ipv6_address);
944         info->network = network;
945
946         connman_network_set_string(network, "Path", path);
947         connman_network_set_name(network, path);
948
949         __create_service(network);
950
951         g_hash_table_insert(network_hash, g_strdup(path), info);
952
953         connman_network_set_available(network, TRUE);
954         connman_network_set_index(network, -1);
955         connman_network_set_bool(network, "Roaming", modem->s_service->roaming);
956
957         if (connman_device_add_network(device, network) != 0) {
958                 g_hash_table_remove(network_hash, path);
959                 return -EIO;
960         }
961
962         active = __set_network_ipconfig(info, prop);
963
964         if (active && (connman_network_get_connecting(network) ||
965                                 connman_network_get_associating(network)))
966                 __set_network_connected(info, active);
967
968         return 0;
969 }
970
971 static void __create_service(struct connman_network *network)
972 {
973         const char *path;
974         char *group;
975
976         DBG("");
977
978         path = connman_network_get_string(network, "Path");
979
980         group = __get_ident(path);
981
982         connman_network_set_group(network, group);
983 }
984
985 static gboolean __set_network_ipconfig(struct telephony_network *network,
986                                         DBusMessageIter *dict)
987 {
988         DBG("set network info");
989
990         gboolean active = FALSE;
991         char *dev_name = NULL, *proxy_addr = NULL;
992         char *ipv4_addr = NULL, *ipv4_gw = NULL, *ipv4_netmask = NULL,
993                                         *ipv4_dns1 = NULL, *ipv4_dns2 = NULL;
994         char *ipv6_addr = NULL, *ipv6_gw = NULL, *ipv6_netmask = NULL,
995                                         *ipv6_dns1 = NULL, *ipv6_dns2 = NULL;
996         int index;
997         int dns_flag = 0;
998
999         while (dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID) {
1000                 DBusMessageIter entry;
1001                 const char *key, *tmp;
1002
1003                 dbus_message_iter_recurse(dict, &entry);
1004                 dbus_message_iter_get_basic(&entry, &key);
1005
1006                 dbus_message_iter_next(&entry);
1007
1008                 DBG("key (%s)", key);
1009
1010                 if (g_str_equal(key, "dev_name") == TRUE) {
1011                         dbus_message_iter_get_basic(&entry, &dev_name);
1012                         DBG("dev_name (%s)", dev_name);
1013                 } else if (g_str_equal(key, "proxy") == TRUE) {
1014                         dbus_message_iter_get_basic(&entry, &proxy_addr);
1015                 } else if (g_str_equal(key, "ipv4_address") == TRUE) {
1016                         dbus_message_iter_get_basic(&entry, &ipv4_addr);
1017                         DBG("ipv4 address (%s)", ipv4_addr);
1018                 } else if (g_str_equal(key, "ipv4_gateway") == TRUE) {
1019                         dbus_message_iter_get_basic(&entry, &ipv4_gw);
1020                 } else if (g_str_equal(key, "ipv4_netmask") == TRUE) {
1021                         dbus_message_iter_get_basic(&entry, &ipv4_netmask);
1022                 } else if (g_str_equal(key, "ipv4_dns1") == TRUE) {
1023                         dbus_message_iter_get_basic(&entry, &ipv4_dns1);
1024                 } else if (g_str_equal(key, "ipv4_dns2") == TRUE) {
1025                         dbus_message_iter_get_basic(&entry, &ipv4_dns2);
1026                 } else if (g_str_equal(key, "ipv6_address") == TRUE) {
1027                         dbus_message_iter_get_basic(&entry, &ipv6_addr);
1028                         DBG("ipv6 address (%s)", ipv6_addr);
1029                 } else if (g_str_equal(key, "ipv6_gateway") == TRUE) {
1030                         dbus_message_iter_get_basic(&entry, &ipv6_gw);
1031                 } else if (g_str_equal(key, "ipv6_netmask") == TRUE) {
1032                         dbus_message_iter_get_basic(&entry, &ipv6_netmask);
1033                 } else if (g_str_equal(key, "ipv6_dns1") == TRUE) {
1034                         dbus_message_iter_get_basic(&entry, &ipv6_dns1);
1035                 } else if (g_str_equal(key, "ipv6_dns2") == TRUE) {
1036                         dbus_message_iter_get_basic(&entry, &ipv6_dns2);
1037                 } else if (g_str_equal(key, "active") == TRUE) {
1038                         dbus_message_iter_get_basic(&entry, &tmp);
1039                         DBG("active (%s)", tmp);
1040                         active = STRING2BOOL(tmp);
1041                 }
1042
1043                 dbus_message_iter_next(dict);
1044         }
1045
1046         /* interface index set */
1047         if (dev_name == NULL)
1048                 dev_name = "";
1049
1050         if (!g_str_equal(dev_name, "")) {
1051                 index = connman_inet_ifindex(dev_name);
1052                 DBG("interface %s, index %d", dev_name, index);
1053                 connman_network_set_index(network->network, index);
1054         }
1055
1056         /* proxy set */
1057         if (proxy_addr == NULL)
1058                 proxy_addr = "";
1059
1060         DBG("proxy (%s) is set", proxy_addr);
1061         connman_network_set_proxy(network->network, proxy_addr);
1062
1063         /* ipv4 set */
1064         if (ipv4_addr == NULL)
1065                 ipv4_addr = "0.0.0.0";
1066
1067         if (g_str_equal(ipv4_addr, "0.0.0.0")) {
1068                 network->ipv4_method = CONNMAN_IPCONFIG_METHOD_OFF;
1069         } else {
1070                 network->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED;
1071                 network->ipv4_address =
1072                         connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
1073                 if (network->ipv4_address == NULL)
1074                         return FALSE;
1075
1076                 connman_ipaddress_set_ipv4(network->ipv4_address, ipv4_addr,
1077                                                 ipv4_netmask, ipv4_gw);
1078
1079                 if (ipv4_dns1 == NULL)
1080                         ipv4_dns1 = "0.0.0.0";
1081                 if (ipv4_dns2 == NULL)
1082                         ipv4_dns2 = "0.0.0.0";
1083
1084                 if (g_str_equal(ipv4_dns1, "0.0.0.0"))
1085                         dns_flag += 1;
1086
1087                 if (g_str_equal(ipv4_dns2, "0.0.0.0"))
1088                         dns_flag += 2;
1089
1090                 gchar *nameservers = NULL;
1091
1092                 switch (dns_flag) {
1093                 case 0:
1094                         nameservers = g_strdup_printf("%s %s", ipv4_dns1,
1095                                                                 ipv4_dns2);
1096                         break;
1097                 case 1:
1098                         nameservers = g_strdup_printf("%s", ipv4_dns2);
1099                         break;
1100                 case 2:
1101                         nameservers = g_strdup_printf("%s", ipv4_dns1);
1102                 }
1103
1104                 connman_network_set_nameservers(network->network, nameservers);
1105                 g_free(nameservers);
1106         }
1107
1108         /* ipv6 set */
1109         if (ipv6_addr == NULL)
1110                 ipv6_addr = "::";
1111
1112         if (g_str_equal(ipv6_addr, "::")) {
1113                 network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF;
1114         } else {
1115                 network->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
1116                 unsigned char prefix_length = 64;
1117                 network->ipv6_address =
1118                         connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
1119                 if (network->ipv6_address == NULL)
1120                         return FALSE;
1121
1122                 connman_ipaddress_set_ipv6(network->ipv6_address, ipv6_addr,
1123                                                 prefix_length, ipv6_gw);
1124
1125                 dns_flag = 0;
1126
1127                 if (ipv6_dns1 == NULL)
1128                         ipv6_dns1 = "::";
1129                 if (ipv6_dns2 == NULL)
1130                         ipv6_dns2 = "::";
1131
1132                 if (g_str_equal(ipv6_dns1, "::"))
1133                         dns_flag += 1;
1134
1135                 if (g_str_equal(ipv6_dns2, "::"))
1136                         dns_flag += 2;
1137
1138                 gchar *nameservers = NULL;
1139
1140                 switch (dns_flag) {
1141                 case 0:
1142                         nameservers = g_strdup_printf("%s %s", ipv6_dns1,
1143                                                                 ipv6_dns2);
1144                         break;
1145                 case 1:
1146                         nameservers = g_strdup_printf("%s", ipv6_dns2);
1147                         break;
1148                 case 2:
1149                         nameservers = g_strdup_printf("%s", ipv6_dns1);
1150                 }
1151
1152                 connman_network_set_nameservers(network->network, nameservers);
1153                 g_free(nameservers);
1154         }
1155
1156         if (active)
1157                 connman_network_set_associating(network->network, TRUE);
1158
1159         return active;
1160 }
1161
1162 static void __set_network_connected(struct telephony_network *network,
1163                                         gboolean connected)
1164 {
1165         gboolean setip = FALSE;
1166
1167         DBG("network %p connected %d", network, connected);
1168
1169         switch (network->ipv4_method) {
1170         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1171         case CONNMAN_IPCONFIG_METHOD_OFF:
1172         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1173         case CONNMAN_IPCONFIG_METHOD_AUTO:
1174                 setip = TRUE;
1175                 break;
1176
1177         case CONNMAN_IPCONFIG_METHOD_FIXED:
1178                 connman_network_set_ipv4_method(network->network,
1179                                                         network->ipv4_method);
1180                 connman_network_set_ipaddress(network->network,
1181                                                         network->ipv4_address);
1182                 setip = TRUE;
1183                 break;
1184
1185         case CONNMAN_IPCONFIG_METHOD_DHCP:
1186                 connman_network_set_ipv4_method(network->network,
1187                                                         network->ipv4_method);
1188                 setip = TRUE;
1189                 break;
1190         }
1191
1192         switch (network->ipv6_method) {
1193         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1194         case CONNMAN_IPCONFIG_METHOD_OFF:
1195         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1196         case CONNMAN_IPCONFIG_METHOD_DHCP:
1197         case CONNMAN_IPCONFIG_METHOD_AUTO:
1198                 DBG("ipv6 not supported");
1199                 break;
1200
1201         case CONNMAN_IPCONFIG_METHOD_FIXED:
1202                 connman_network_set_ipv6_method(network->network,
1203                                                         network->ipv6_method);
1204                 connman_network_set_ipaddress(network->network,
1205                                                         network->ipv6_address);
1206                 setip = TRUE;
1207                 break;
1208         }
1209
1210         if (setip == TRUE)
1211                 connman_network_set_connected(network->network, connected);
1212
1213         return;
1214 }
1215
1216 static char *__get_ident(const char *path)
1217 {
1218         char *pos;
1219
1220         if (*path != '/')
1221                 return NULL;
1222
1223         pos = strrchr(path, '/');
1224         if (pos == NULL)
1225                 return NULL;
1226
1227         return pos + 1;
1228 }
1229
1230 static gboolean __changed_modem(DBusConnection *connection,
1231                                 DBusMessage *message, void *user_data)
1232 {
1233         DBG("modem changed signal");
1234
1235         DBusMessageIter args, dict;
1236         const char *path = dbus_message_get_path(message);
1237         struct telephony_modem *modem;
1238
1239         DBG("modem path %s", path);
1240
1241         modem = g_hash_table_lookup(modem_hash, path);
1242         if (modem == NULL) {
1243                 DBG("modem object does not exists");
1244                 return TRUE;
1245         }
1246
1247         DBG("message signature (%s)", dbus_message_get_signature(message));
1248
1249         if (dbus_message_iter_init(message, &args) == FALSE) {
1250                 DBG("error to read message");
1251                 return TRUE;
1252         }
1253
1254         dbus_message_iter_recurse(&args, &dict);
1255
1256         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
1257                 DBusMessageIter entry;
1258                 const char *key, *tmp;
1259
1260                 dbus_message_iter_recurse(&dict, &entry);
1261                 dbus_message_iter_get_basic(&entry, &key);
1262
1263                 dbus_message_iter_next(&entry);
1264                 dbus_message_iter_get_basic(&entry, &tmp);
1265
1266                 DBG("key(%s), value(%s)", key, tmp);
1267
1268                 if (g_str_equal(key, "powered") == TRUE) {
1269                         modem->powered = STRING2BOOL(tmp);
1270                 } else if (g_str_equal(key, "operator") == TRUE) {
1271                         modem->operator = g_strdup(tmp);
1272                 } else if (g_str_equal(key, "sim_init") == TRUE) {
1273                         modem->sim_init = STRING2BOOL(tmp);
1274                 } else if (g_str_equal(key, "flight_mode") == TRUE) {
1275                         modem->flight_mode = STRING2BOOL(tmp);
1276                 } else if (g_str_equal(key, "roaming_allowed") == TRUE) {
1277                         modem->roaming_allowed = STRING2BOOL(tmp);
1278                 } else if (g_str_equal(key, "data_allowed") == TRUE) {
1279                         modem->data_allowed = STRING2BOOL(tmp);
1280                 }
1281
1282                 dbus_message_iter_next(&dict);
1283         }
1284
1285         if (modem->device == NULL)
1286                 __add_connman_device(path, modem->operator);
1287
1288         __set_device_powered(modem, modem->powered);
1289
1290         if (modem->powered != TRUE) {
1291                 DBG("modem is not powered");
1292                 return TRUE;
1293         }
1294
1295         if (!modem->s_service) {
1296                 __request_get_services(modem->path);
1297                 return TRUE;
1298         }
1299
1300         if (modem->flight_mode || !modem->data_allowed) {
1301                 DBG("modem(%s) flight mode(%d) data allowed(%d)",
1302                         modem->path, modem->flight_mode, modem->data_allowed);
1303                 return TRUE;
1304         }
1305
1306         return TRUE;
1307 }
1308
1309 static gboolean __added_modem(DBusConnection *connection,
1310                                 DBusMessage *message, void *user_data)
1311 {
1312         DBG("modem added signal");
1313
1314         const char *modem_path = NULL;
1315         DBusMessageIter args, dict, tmp;
1316
1317         DBG("message signature (%s)", dbus_message_get_signature(message));
1318         if (dbus_message_iter_init(message, &args) == FALSE) {
1319                 DBG("error to read message");
1320                 return TRUE;
1321         }
1322
1323         dbus_message_iter_recurse(&args, &dict);
1324         memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
1325
1326         while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
1327                 DBusMessageIter entry;
1328                 const char *key, *value;
1329
1330                 dbus_message_iter_recurse(&tmp, &entry);
1331                 dbus_message_iter_get_basic(&entry, &key);
1332
1333                 dbus_message_iter_next(&entry);
1334                 dbus_message_iter_get_basic(&entry, &value);
1335
1336                 DBG("key (%s) value(%s)", key, value);
1337
1338                 if (g_str_equal(key, "path") == TRUE)
1339                         modem_path = g_strdup(value);
1340
1341                 dbus_message_iter_next(&tmp);
1342         }
1343
1344         if (modem_path != NULL)
1345                 __add_modem(modem_path, &dict);
1346
1347         return TRUE;
1348 }
1349
1350 static gboolean __removed_modem(DBusConnection *connection,
1351                                         DBusMessage *message, void *user_data)
1352 {
1353         DBG("modem removed signal");
1354
1355         DBusMessageIter iter;
1356         const char *modem_path;
1357
1358         if (dbus_message_iter_init(message, &iter) == FALSE) {
1359                 DBG("error to read message");
1360                 return TRUE;
1361         }
1362
1363         dbus_message_iter_get_basic(&iter, &modem_path);
1364         g_hash_table_remove(modem_hash, modem_path);
1365
1366         return TRUE;
1367 }
1368
1369 static gboolean __changed_service(DBusConnection *connection,
1370                                         DBusMessage *message, void *user_data)
1371 {
1372         DBG("service changed signal");
1373
1374         DBusMessageIter args, dict;
1375         const char *service_path = dbus_message_get_path(message);
1376         struct telephony_modem *modem;
1377         struct telephony_service *s_service;
1378         gboolean roaming_option = TRUE;
1379
1380         DBG("service path %s", service_path);
1381
1382         s_service = g_hash_table_lookup(service_hash, service_path);
1383         if (s_service == NULL) {
1384                 DBG("service object does not exists");
1385                 return TRUE;
1386         }
1387
1388         modem = s_service->p_modem;
1389         if (modem == NULL) {
1390                 DBG("modem object does not exists");
1391                 return TRUE;
1392         }
1393
1394         DBG("message signature (%s)", dbus_message_get_signature(message));
1395
1396         if (dbus_message_iter_init(message, &args) == FALSE) {
1397                 DBG("error to read message");
1398                 return TRUE;
1399         }
1400
1401         dbus_message_iter_recurse(&args, &dict);
1402
1403         while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
1404                 DBusMessageIter entry;
1405                 const char *key, *tmp;
1406
1407                 dbus_message_iter_recurse(&dict, &entry);
1408                 dbus_message_iter_get_basic(&entry, &key);
1409
1410                 dbus_message_iter_next(&entry);
1411                 dbus_message_iter_get_basic(&entry, &tmp);
1412
1413                 DBG("key(%s), value(%s)", key, tmp);
1414
1415                 if (g_str_equal(key, "roaming") == TRUE) {
1416                         s_service->roaming = STRING2BOOL(tmp);
1417                 } else if (g_str_equal(key, "act") == TRUE) {
1418                         s_service->act = g_strdup(tmp);
1419                 } else if (g_str_equal(key, "ps_attached") == TRUE) {
1420                         s_service->ps_attached = STRING2BOOL(tmp);
1421                 }
1422
1423                 dbus_message_iter_next(&dict);
1424         }
1425
1426         roaming_option &= (!s_service->roaming && !modem->roaming_allowed)
1427                                 || modem->roaming_allowed;
1428
1429         return TRUE;
1430 }
1431
1432
1433 static gboolean __added_service(DBusConnection *connection,
1434                                 DBusMessage *message, void *user_data)
1435 {
1436         DBG("service added signal");
1437
1438         const char *path = dbus_message_get_path(message);
1439         const char *service_path = NULL;
1440         DBusMessageIter args, dict, tmp;
1441         struct telephony_modem *modem;
1442
1443         modem = g_hash_table_lookup(modem_hash, path);
1444         if (modem == NULL || modem->device == NULL)
1445                 return TRUE;
1446
1447         DBG("message signature (%s)", dbus_message_get_signature(message));
1448         if (dbus_message_iter_init(message, &args) == FALSE) {
1449                 DBG("error to read message");
1450                 return TRUE;
1451         }
1452
1453         dbus_message_iter_recurse(&args, &dict);
1454         memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
1455
1456         while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
1457                 DBusMessageIter entry;
1458                 const char *key, *value;
1459
1460                 dbus_message_iter_recurse(&tmp, &entry);
1461                 dbus_message_iter_get_basic(&entry, &key);
1462
1463                 dbus_message_iter_next(&entry);
1464                 dbus_message_iter_get_basic(&entry, &value);
1465
1466                 DBG("key (%s) value(%s)", key, value);
1467
1468                 if (g_str_equal(key, "path") == TRUE) {
1469                         service_path = g_strdup(value);
1470                 }
1471
1472                 dbus_message_iter_next(&tmp);
1473         }
1474
1475         if (service_path != NULL)
1476                 __add_service(modem, service_path, &dict);
1477
1478         return TRUE;
1479 }
1480
1481 static gboolean __removed_service(DBusConnection *connection,
1482                                         DBusMessage *message, void *user_data)
1483 {
1484         DBG("service removed signal");
1485
1486         DBusMessageIter iter;
1487         const char *service_path;
1488
1489         if (dbus_message_iter_init(message, &iter) == FALSE) {
1490                 DBG("error to read message");
1491                 return TRUE;
1492         }
1493
1494         dbus_message_iter_get_basic(&iter, &service_path);
1495         g_hash_table_remove(service_hash, service_path);
1496
1497         return TRUE;
1498 }
1499
1500 static gboolean __changed_context(DBusConnection *connection,
1501                                         DBusMessage *message, void *user_data)
1502 {
1503         DBG("network changed signal");
1504
1505         gboolean active = FALSE;
1506         const char *path = dbus_message_get_path(message);
1507         struct telephony_network *info;
1508         DBusMessageIter args, dict;
1509
1510         DBG("path %s", path);
1511         info = g_hash_table_lookup(network_hash, path);
1512         if (info == NULL)
1513                 return TRUE;
1514
1515         if (!__check_network_available(info->network)) {
1516                 g_hash_table_remove(network_hash, path);
1517                 return TRUE;
1518         }
1519
1520         if (dbus_message_iter_init(message, &args) == FALSE) {
1521                 DBG("error to read message");
1522                 return TRUE;
1523         }
1524
1525         dbus_message_iter_recurse(&args, &dict);
1526
1527         active = __set_network_ipconfig(info, &dict);
1528
1529         if (active == FALSE)
1530                 __set_network_connected(info, active);
1531         else if ((connman_network_get_connecting(info->network) ||
1532                         connman_network_get_associating(info->network)))
1533                 __set_network_connected(info, active);
1534
1535         return TRUE;
1536 }
1537
1538 static gboolean __added_context(DBusConnection *connection,
1539                                         DBusMessage *message, void *user_data)
1540 {
1541         DBG("network added signal");
1542
1543         DBusMessageIter args, dict, tmp;
1544         const char *path = dbus_message_get_path(message);
1545         const char *network_path = NULL;
1546         struct telephony_service *service = NULL;
1547         struct telephony_modem *modem = NULL;
1548
1549         service = g_hash_table_lookup(service_hash, path);
1550         if (service == NULL || service->p_modem == NULL)
1551                 return TRUE;
1552
1553         modem = service->p_modem;
1554         if (modem == NULL || modem->device == NULL)
1555                 return TRUE;
1556
1557         DBG("message signature (%s)", dbus_message_get_signature(message));
1558         if (dbus_message_iter_init(message, &args) == FALSE) {
1559                 DBG("error to read message");
1560                 return TRUE;
1561         }
1562
1563         dbus_message_iter_recurse(&args, &dict);
1564         memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
1565
1566         while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
1567                 DBusMessageIter entry;
1568                 const char *key, *value;
1569
1570                 dbus_message_iter_recurse(&tmp, &entry);
1571                 dbus_message_iter_get_basic(&entry, &key);
1572
1573                 dbus_message_iter_next(&entry);
1574                 dbus_message_iter_get_basic(&entry, &value);
1575
1576                 DBG("key (%s) value(%s)", key, value);
1577
1578                 if (g_str_equal(key, "path") == TRUE)
1579                         network_path = g_strdup(value);
1580
1581                 dbus_message_iter_next(&tmp);
1582         }
1583
1584         if (network_path != NULL)
1585                 __add_context(modem->device, network_path, &dict);
1586
1587         return TRUE;
1588 }
1589
1590 static gboolean __removed_context(DBusConnection *connection,
1591                                         DBusMessage *message, void *user_data)
1592 {
1593         DBG("network removed signal");
1594
1595         DBusMessageIter iter;
1596         const char *path = dbus_message_get_path(message);
1597         const char *network_path = NULL;
1598         struct telephony_service *service = NULL;
1599
1600         service = g_hash_table_lookup(service_hash, path);
1601         if (service == NULL || service->p_modem == NULL)
1602                 return TRUE;
1603
1604         if (dbus_message_iter_init(message, &iter) == FALSE) {
1605                 DBG("error to read message");
1606                 return TRUE;
1607         }
1608
1609         dbus_message_iter_get_basic(&iter, &network_path);
1610         g_hash_table_remove(network_hash, network_path);
1611
1612         return TRUE;
1613 }
1614
1615 /* telephony initialization */
1616 static guint watch;
1617 static guint modem_watch;
1618 static guint modem_added_watch;
1619 static guint modem_removed_watch;
1620 static guint service_watch;
1621 static guint service_added_watch;
1622 static guint service_removed_watch;
1623 static guint context_watch;
1624 static guint context_added_watch;
1625 static guint context_removed_watch;
1626
1627 static int telephony_init(void)
1628 {
1629         DBG("telephony plugin");
1630         int err;
1631
1632         connection = connman_dbus_get_connection();
1633         if (connection == NULL)
1634                 return -EIO;
1635
1636         /* telephony watch */
1637         watch = g_dbus_add_service_watch(connection, PS_DBUS_SERVICE,
1638                                         telephony_connect, telephony_disconnect,
1639                                         NULL, NULL);
1640
1641         modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1642                                                 PS_MODEM_INTERFACE,
1643                                                 PROPERTY_CHANGED,
1644                                                 __changed_modem, NULL, NULL);
1645
1646         modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1647                                                 PS_MASTER_INTERFACE,
1648                                                 MODEM_ADDED, __added_modem,
1649                                                 NULL, NULL);
1650
1651         modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1652                                                 PS_MASTER_INTERFACE,
1653                                                 MODEM_REMOVED, __removed_modem,
1654                                                 NULL, NULL);
1655
1656         service_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1657                                                 PS_SERVICE_INTERFACE,
1658                                                 PROPERTY_CHANGED,
1659                                                 __changed_service,
1660                                                 NULL, NULL);
1661
1662         service_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1663                                                 PS_MODEM_INTERFACE,
1664                                                 SERVICE_ADDED, __added_service,
1665                                                 NULL, NULL);
1666
1667         service_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1668                                                 PS_MODEM_INTERFACE,
1669                                                 SERVICE_REMOVED,
1670                                                 __removed_service,
1671                                                 NULL, NULL);
1672
1673         context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1674                                                 PS_CONTEXT_INTERFACE,
1675                                                 PROPERTY_CHANGED,
1676                                                 __changed_context,
1677                                                 NULL, NULL);
1678
1679         context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1680                                                 PS_SERVICE_INTERFACE,
1681                                                 CONTEXT_ADDED, __added_context,
1682                                                 NULL, NULL);
1683
1684         context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
1685                                                 PS_SERVICE_INTERFACE,
1686                                                 CONTEXT_REMOVED,
1687                                                 __removed_context,
1688                                                 NULL, NULL);
1689
1690         if (watch == 0 || modem_watch == 0 || modem_added_watch == 0
1691                         || modem_removed_watch == 0 || service_watch == 0
1692                         || service_added_watch == 0 || context_watch == 0
1693                         || service_removed_watch == 0
1694                         || context_added_watch == 0
1695                         || context_removed_watch == 0) {
1696                 err = -EIO;
1697                 goto remove;
1698         }
1699
1700         err = connman_network_driver_register(&network_driver);
1701         if (err < 0)
1702                 goto remove;
1703
1704         err = connman_device_driver_register(&modem_driver);
1705         if (err < 0) {
1706                 connman_network_driver_unregister(&network_driver);
1707                 goto remove;
1708         }
1709
1710         err = connman_technology_driver_register(&tech_driver);
1711         if (err < 0) {
1712                 connman_device_driver_unregister(&modem_driver);
1713                 connman_network_driver_unregister(&network_driver);
1714                 goto remove;
1715         }
1716
1717         return 0;
1718
1719 remove:
1720         g_dbus_remove_watch(connection, watch);
1721         g_dbus_remove_watch(connection, modem_watch);
1722         g_dbus_remove_watch(connection, modem_added_watch);
1723         g_dbus_remove_watch(connection, modem_removed_watch);
1724         g_dbus_remove_watch(connection, service_watch);
1725         g_dbus_remove_watch(connection, service_added_watch);
1726         g_dbus_remove_watch(connection, service_removed_watch);
1727         g_dbus_remove_watch(connection, context_watch);
1728         g_dbus_remove_watch(connection, context_added_watch);
1729         g_dbus_remove_watch(connection, context_removed_watch);
1730
1731         dbus_connection_unref(connection);
1732         return err;
1733 }
1734
1735 static void telephony_exit(void)
1736 {
1737         g_dbus_remove_watch(connection, watch);
1738         g_dbus_remove_watch(connection, modem_watch);
1739         g_dbus_remove_watch(connection, modem_added_watch);
1740         g_dbus_remove_watch(connection, modem_removed_watch);
1741         g_dbus_remove_watch(connection, service_watch);
1742         g_dbus_remove_watch(connection, service_added_watch);
1743         g_dbus_remove_watch(connection, service_removed_watch);
1744         g_dbus_remove_watch(connection, context_watch);
1745         g_dbus_remove_watch(connection, context_added_watch);
1746         g_dbus_remove_watch(connection, context_removed_watch);
1747
1748         telephony_disconnect(connection, NULL);
1749
1750         connman_device_driver_unregister(&modem_driver);
1751         connman_network_driver_unregister(&network_driver);
1752
1753         dbus_connection_unref(connection);
1754 }
1755
1756 CONNMAN_PLUGIN_DEFINE(telephony, "Samsung Telephony Framework plug-in", VERSION,
1757                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, telephony_init, telephony_exit)