Fix wrong variable reference when sending technology replies
[platform/upstream/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. 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 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gdbus.h>
27
28 #include "connman.h"
29
30 static connman_bool_t global_offlinemode = FALSE;
31
32 connman_bool_t __connman_manager_get_offlinemode(void)
33 {
34         return global_offlinemode;
35 }
36
37 static void append_profiles(DBusMessageIter *dict)
38 {
39         DBusMessageIter entry, value, iter;
40         const char *key = "Profiles";
41
42         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
43                                                                 NULL, &entry);
44
45         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
46
47         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
48                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
49                                                                 &value);
50
51         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
52                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
53         __connman_profile_list(&iter);
54         dbus_message_iter_close_container(&value, &iter);
55
56         dbus_message_iter_close_container(&entry, &value);
57
58         dbus_message_iter_close_container(dict, &entry);
59 }
60
61 static void append_services(DBusMessageIter *dict)
62 {
63         DBusMessageIter entry, value, iter;
64         const char *key = "Services";
65
66         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
67                                                                 NULL, &entry);
68
69         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
70
71         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
72                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
73                                                                 &value);
74
75         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
76                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
77         __connman_service_list(&iter);
78         dbus_message_iter_close_container(&value, &iter);
79
80         dbus_message_iter_close_container(&entry, &value);
81
82         dbus_message_iter_close_container(dict, &entry);
83 }
84
85 static void append_devices(DBusMessageIter *dict)
86 {
87         DBusMessageIter entry, value, iter;
88         const char *key = "Devices";
89
90         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
91                                                                 NULL, &entry);
92
93         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
94
95         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
96                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
97                                                                 &value);
98
99         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
100                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
101         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
102         dbus_message_iter_close_container(&value, &iter);
103
104         dbus_message_iter_close_container(&entry, &value);
105
106         dbus_message_iter_close_container(dict, &entry);
107 }
108
109 static void append_connections(DBusMessageIter *dict)
110 {
111         DBusMessageIter entry, value, iter;
112         const char *key = "Connections";
113
114         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
115                                                                 NULL, &entry);
116
117         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
118
119         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
120                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
121                                                                 &value);
122
123         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
124                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
125         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
126         dbus_message_iter_close_container(&value, &iter);
127
128         dbus_message_iter_close_container(&entry, &value);
129
130         dbus_message_iter_close_container(dict, &entry);
131 }
132
133 static void append_available_technologies(DBusMessageIter *dict)
134 {
135         DBusMessageIter entry, value, iter;
136         const char *key = "AvailableTechnologies";
137
138         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
139                                                                 NULL, &entry);
140
141         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
142
143         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
144                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
145                                                                 &value);
146
147         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
148                                         DBUS_TYPE_STRING_AS_STRING, &iter);
149         __connman_notifier_list_registered(&iter);
150         dbus_message_iter_close_container(&value, &iter);
151
152         dbus_message_iter_close_container(&entry, &value);
153
154         dbus_message_iter_close_container(dict, &entry);
155 }
156
157 static void append_enabled_technologies(DBusMessageIter *dict)
158 {
159         DBusMessageIter entry, value, iter;
160         const char *key = "EnabledTechnologies";
161
162         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
163                                                                 NULL, &entry);
164
165         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
166
167         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
168                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
169                                                                 &value);
170
171         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
172                                         DBUS_TYPE_STRING_AS_STRING, &iter);
173         __connman_notifier_list_enabled(&iter);
174         dbus_message_iter_close_container(&value, &iter);
175
176         dbus_message_iter_close_container(&entry, &value);
177
178         dbus_message_iter_close_container(dict, &entry);
179 }
180
181 static void append_connected_technologies(DBusMessageIter *dict)
182 {
183         DBusMessageIter entry, value, iter;
184         const char *key = "ConnectedTechnologies";
185
186         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
187                                                                 NULL, &entry);
188
189         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
190
191         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
192                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
193                                                                 &value);
194
195         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
196                                         DBUS_TYPE_STRING_AS_STRING, &iter);
197         __connman_notifier_list_connected(&iter);
198         dbus_message_iter_close_container(&value, &iter);
199
200         dbus_message_iter_close_container(&entry, &value);
201
202         dbus_message_iter_close_container(dict, &entry);
203 }
204
205 static DBusMessage *get_properties(DBusConnection *conn,
206                                         DBusMessage *msg, void *data)
207 {
208         DBusMessage *reply;
209         DBusMessageIter array, dict;
210         const char *str;
211
212         DBG("conn %p", conn);
213
214         if (__connman_security_check_privilege(msg,
215                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
216                 return __connman_error_permission_denied(msg);
217
218         reply = dbus_message_new_method_return(msg);
219         if (reply == NULL)
220                 return NULL;
221
222         dbus_message_iter_init_append(reply, &array);
223
224         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
225                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
226                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
227                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
228
229         str = __connman_profile_active_path();
230         if (str != NULL)
231                 connman_dbus_dict_append_variant(&dict, "ActiveProfile",
232                                                 DBUS_TYPE_OBJECT_PATH, &str);
233
234         append_profiles(&dict);
235         append_services(&dict);
236
237         append_devices(&dict);
238         append_connections(&dict);
239
240         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
241                 str = "online";
242         else
243                 str = "offline";
244
245         connman_dbus_dict_append_variant(&dict, "State",
246                                                 DBUS_TYPE_STRING, &str);
247
248         connman_dbus_dict_append_variant(&dict, "OfflineMode",
249                                 DBUS_TYPE_BOOLEAN, &global_offlinemode);
250
251         append_available_technologies(&dict);
252         append_enabled_technologies(&dict);
253         append_connected_technologies(&dict);
254
255         str = __connman_service_default();
256         if (str != NULL)
257                 connman_dbus_dict_append_variant(&dict, "DefaultTechnology",
258                                                 DBUS_TYPE_STRING, &str);
259
260         dbus_message_iter_close_container(&array, &dict);
261
262         return reply;
263 }
264
265 static DBusMessage *set_property(DBusConnection *conn,
266                                         DBusMessage *msg, void *data)
267 {
268         DBusMessageIter iter, value;
269         const char *name;
270
271         DBG("conn %p", conn);
272
273         if (dbus_message_iter_init(msg, &iter) == FALSE)
274                 return __connman_error_invalid_arguments(msg);
275
276         dbus_message_iter_get_basic(&iter, &name);
277         dbus_message_iter_next(&iter);
278         dbus_message_iter_recurse(&iter, &value);
279
280         if (__connman_security_check_privilege(msg,
281                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
282                 return __connman_error_permission_denied(msg);
283
284         if (g_str_equal(name, "OfflineMode") == TRUE) {
285                 connman_bool_t offlinemode;
286
287                 dbus_message_iter_get_basic(&value, &offlinemode);
288
289                 if (global_offlinemode == offlinemode)
290                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
291
292                 global_offlinemode = offlinemode;
293
294                 __connman_storage_save_global();
295
296                 __connman_device_set_offlinemode(offlinemode);
297         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
298                 const char *str;
299
300                 dbus_message_iter_get_basic(&value, &str);
301
302                 return __connman_error_not_supported(msg);
303         } else
304                 return __connman_error_invalid_property(msg);
305
306         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
307 }
308
309 static DBusMessage *get_state(DBusConnection *conn,
310                                         DBusMessage *msg, void *data)
311 {
312         const char *str;
313
314         DBG("conn %p", conn);
315
316         if (__connman_security_check_privilege(msg,
317                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
318                 return __connman_error_permission_denied(msg);
319
320         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
321                 str = "online";
322         else
323                 str = "offline";
324
325         return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &str,
326                                                 DBUS_TYPE_INVALID);
327 }
328
329 static DBusMessage *add_profile(DBusConnection *conn,
330                                         DBusMessage *msg, void *data)
331 {
332         const char *name;
333
334         DBG("conn %p", conn);
335
336         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
337                                                         DBUS_TYPE_INVALID);
338
339         return __connman_error_not_supported(msg);
340 }
341
342 static DBusMessage *remove_profile(DBusConnection *conn,
343                                         DBusMessage *msg, void *data)
344 {
345         const char *path;
346
347         DBG("conn %p", conn);
348
349         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
350                                                         DBUS_TYPE_INVALID);
351
352         return __connman_error_not_supported(msg);
353 }
354
355 static DBusMessage *request_scan(DBusConnection *conn,
356                                         DBusMessage *msg, void *data)
357 {
358         enum connman_service_type type;
359         const char *str;
360         int err;
361
362         DBG("conn %p", conn);
363
364         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
365                                                         DBUS_TYPE_INVALID);
366
367         if (g_strcmp0(str, "") == 0)
368                 type = CONNMAN_SERVICE_TYPE_UNKNOWN;
369         else if (g_strcmp0(str, "wifi") == 0)
370                 type = CONNMAN_SERVICE_TYPE_WIFI;
371         else if (g_strcmp0(str, "wimax") == 0)
372                 type = CONNMAN_SERVICE_TYPE_WIMAX;
373         else
374                 return __connman_error_invalid_arguments(msg);
375
376         err = __connman_element_request_scan(type);
377         if (err < 0) {
378                 if (err == -EINPROGRESS) {
379                         connman_error("Invalid return code from scan");
380                         err = -EINVAL;
381                 }
382
383                 return __connman_error_failed(msg, -err);
384         }
385
386         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
387 }
388
389 static DBusConnection *connection = NULL;
390
391 static enum connman_service_type technology_type;
392 static connman_bool_t technology_enabled;
393 static DBusMessage *technology_pending = NULL;
394 static guint technology_timeout = 0;
395
396 static void technology_reply(int error)
397 {
398         DBG("");
399
400         if (technology_timeout > 0) {
401                 g_source_remove(technology_timeout);
402                 technology_timeout = 0;
403         }
404
405         if (technology_pending != NULL) {
406                 if (error > 0) {
407                         DBusMessage *reply;
408
409                         reply = __connman_error_failed(technology_pending,
410                                                                 error);
411                         if (reply != NULL)
412                                 g_dbus_send_message(connection, reply);
413                 } else
414                         g_dbus_send_reply(connection, technology_pending,
415                                                         DBUS_TYPE_INVALID);
416
417                 dbus_message_unref(technology_pending);
418                 technology_pending = NULL;
419         }
420
421         technology_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
422 }
423
424 static gboolean technology_abort(gpointer user_data)
425 {
426         DBG("");
427
428         technology_timeout = 0;
429
430         technology_reply(ETIMEDOUT);
431
432         return FALSE;
433 }
434
435 static void technology_notify(enum connman_service_type type,
436                                                 connman_bool_t enabled)
437 {
438         DBG("type %d enabled %d", type, enabled);
439
440         if (type == technology_type && enabled == technology_enabled)
441                 technology_reply(0);
442 }
443
444 static struct connman_notifier technology_notifier = {
445         .name           = "manager",
446         .priority       = CONNMAN_NOTIFIER_PRIORITY_HIGH,
447         .service_enabled= technology_notify,
448 };
449
450 static DBusMessage *enable_technology(DBusConnection *conn,
451                                         DBusMessage *msg, void *data)
452 {
453         enum connman_service_type type;
454         const char *str;
455         int err;
456
457         DBG("conn %p", conn);
458
459         if (technology_pending != NULL)
460                 return __connman_error_in_progress(msg);
461
462         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
463                                                         DBUS_TYPE_INVALID);
464
465         if (g_strcmp0(str, "ethernet") == 0)
466                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
467         else if (g_strcmp0(str, "wifi") == 0)
468                 type = CONNMAN_SERVICE_TYPE_WIFI;
469         else if (g_strcmp0(str, "wimax") == 0)
470                 type = CONNMAN_SERVICE_TYPE_WIMAX;
471         else if (g_strcmp0(str, "bluetooth") == 0)
472                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
473         else if (g_strcmp0(str, "cellular") == 0)
474                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
475         else
476                 return __connman_error_invalid_arguments(msg);
477
478         if (__connman_notifier_is_enabled(type) == TRUE)
479                 return __connman_error_already_enabled(msg);
480
481         technology_type = type;
482         technology_enabled = TRUE;
483         technology_pending = dbus_message_ref(msg);
484
485         err = __connman_element_enable_technology(type);
486         if (err < 0 && err != -EINPROGRESS)
487                 technology_reply(-err);
488         else
489                 technology_timeout = g_timeout_add_seconds(15,
490                                                 technology_abort, NULL);
491
492         return NULL;
493 }
494
495 static DBusMessage *disable_technology(DBusConnection *conn,
496                                         DBusMessage *msg, void *data)
497 {
498         enum connman_service_type type;
499         const char *str;
500         int err;
501
502         DBG("conn %p", conn);
503
504         if (technology_pending != NULL)
505                 return __connman_error_in_progress(msg);
506
507         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
508                                                         DBUS_TYPE_INVALID);
509
510         if (g_strcmp0(str, "ethernet") == 0)
511                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
512         else if (g_strcmp0(str, "wifi") == 0)
513                 type = CONNMAN_SERVICE_TYPE_WIFI;
514         else if (g_strcmp0(str, "wimax") == 0)
515                 type = CONNMAN_SERVICE_TYPE_WIMAX;
516         else if (g_strcmp0(str, "bluetooth") == 0)
517                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
518         else if (g_strcmp0(str, "cellular") == 0)
519                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
520         else
521                 return __connman_error_invalid_arguments(msg);
522
523         if (__connman_notifier_is_enabled(type) == FALSE)
524                 return __connman_error_already_disabled(msg);
525
526         technology_type = type;
527         technology_enabled = FALSE;
528         technology_pending = dbus_message_ref(msg);
529
530         err = __connman_element_disable_technology(type);
531         if (err < 0 && err != -EINPROGRESS)
532                 technology_reply(-err);
533         else
534                 technology_timeout = g_timeout_add_seconds(10,
535                                                 technology_abort, NULL);
536
537         return NULL;
538 }
539
540 static DBusMessage *connect_service(DBusConnection *conn,
541                                         DBusMessage *msg, void *data)
542 {
543         int err;
544
545         DBG("conn %p", conn);
546
547         if (__connman_security_check_privilege(msg,
548                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
549                 return __connman_error_permission_denied(msg);
550
551         err = __connman_service_create_and_connect(msg);
552         if (err < 0) {
553                 if (err == -EINPROGRESS) {
554                         connman_error("Invalid return code from connect");
555                         err = -EINVAL;
556                 }
557
558                 return __connman_error_failed(msg, -err);
559         }
560
561         return NULL;
562 }
563
564 static DBusMessage *register_agent(DBusConnection *conn,
565                                         DBusMessage *msg, void *data)
566 {
567         DBusMessage *reply;
568         const char *sender, *path;
569
570         DBG("conn %p", conn);
571
572         sender = dbus_message_get_sender(msg);
573
574         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
575                                                         DBUS_TYPE_INVALID);
576
577         reply = dbus_message_new_method_return(msg);
578         if (reply == NULL)
579                 return NULL;
580
581         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
582
583         __connman_agent_register(sender, path);
584
585         return reply;
586 }
587
588 static DBusMessage *unregister_agent(DBusConnection *conn,
589                                         DBusMessage *msg, void *data)
590 {
591         DBusMessage *reply;
592         const char *sender, *path;
593
594         DBG("conn %p", conn);
595
596         sender = dbus_message_get_sender(msg);
597
598         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
599                                                         DBUS_TYPE_INVALID);
600
601         reply = dbus_message_new_method_return(msg);
602         if (reply == NULL)
603                 return NULL;
604
605         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
606
607         __connman_agent_unregister(sender, path);
608
609         return reply;
610 }
611
612 static GDBusMethodTable manager_methods[] = {
613         { "GetProperties",     "",      "a{sv}", get_properties     },
614         { "SetProperty",       "sv",    "",      set_property       },
615         { "GetState",          "",      "s",     get_state          },
616         { "AddProfile",        "s",     "o",     add_profile        },
617         { "RemoveProfile",     "o",     "",      remove_profile     },
618         { "RequestScan",       "s",     "",      request_scan       },
619         { "EnableTechnology",  "s",     "",      enable_technology,
620                                                 G_DBUS_METHOD_FLAG_ASYNC },
621         { "DisableTechnology", "s",     "",      disable_technology,
622                                                 G_DBUS_METHOD_FLAG_ASYNC },
623         { "ConnectService",    "a{sv}", "o",     connect_service,
624                                                 G_DBUS_METHOD_FLAG_ASYNC },
625         { "RegisterAgent",     "o",     "",      register_agent     },
626         { "UnregisterAgent",   "o",     "",      unregister_agent   },
627         { },
628 };
629
630 static GDBusSignalTable manager_signals[] = {
631         { "PropertyChanged", "sv" },
632         { "StateChanged",    "s"  },
633         { },
634 };
635
636 static DBusMessage *nm_sleep(DBusConnection *conn,
637                                         DBusMessage *msg, void *data)
638 {
639         DBusMessage *reply;
640
641         DBG("conn %p", conn);
642
643         reply = dbus_message_new_method_return(msg);
644         if (reply == NULL)
645                 return NULL;
646
647         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
648
649         return reply;
650 }
651
652 static DBusMessage *nm_wake(DBusConnection *conn,
653                                         DBusMessage *msg, void *data)
654 {
655         DBusMessage *reply;
656
657         DBG("conn %p", conn);
658
659         reply = dbus_message_new_method_return(msg);
660         if (reply == NULL)
661                 return NULL;
662
663         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
664
665         return reply;
666 }
667
668 enum {
669         NM_STATE_UNKNOWN = 0,
670         NM_STATE_ASLEEP,
671         NM_STATE_CONNECTING,
672         NM_STATE_CONNECTED,
673         NM_STATE_DISCONNECTED
674 };
675
676 static DBusMessage *nm_state(DBusConnection *conn,
677                                         DBusMessage *msg, void *data)
678 {
679         DBusMessage *reply;
680         dbus_uint32_t state;
681
682         DBG("conn %p", conn);
683
684         reply = dbus_message_new_method_return(msg);
685         if (reply == NULL)
686                 return NULL;
687
688         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
689                 state = NM_STATE_CONNECTED;
690         else
691                 state = NM_STATE_DISCONNECTED;
692
693         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
694                                                         DBUS_TYPE_INVALID);
695
696         return reply;
697 }
698
699 static GDBusMethodTable nm_methods[] = {
700         { "sleep", "",  "",   nm_sleep        },
701         { "wake",  "",  "",   nm_wake         },
702         { "state", "",  "u",  nm_state        },
703         { },
704 };
705
706 static int manager_load(void)
707 {
708         GKeyFile *keyfile;
709         GError *error = NULL;
710         connman_bool_t offlinemode;
711
712         DBG("");
713
714         keyfile = __connman_storage_open();
715         if (keyfile == NULL)
716                 return -EIO;
717
718         offlinemode = g_key_file_get_boolean(keyfile, "global",
719                                                 "OfflineMode", &error);
720         if (error == NULL) {
721                 global_offlinemode = offlinemode;
722
723                 __connman_device_set_offlinemode(offlinemode);
724         }
725         g_clear_error(&error);
726
727         __connman_storage_close(keyfile, FALSE);
728
729         return 0;
730 }
731
732 static int manager_save(void)
733 {
734         GKeyFile *keyfile;
735
736         DBG("");
737
738         keyfile = __connman_storage_open();
739         if (keyfile == NULL)
740                 return -EIO;
741
742         g_key_file_set_boolean(keyfile, "global",
743                                         "OfflineMode", global_offlinemode);
744
745         __connman_storage_close(keyfile, TRUE);
746
747         return 0;
748 }
749
750 static struct connman_storage manager_storage = {
751         .name           = "manager",
752         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
753         .global_load    = manager_load,
754         .global_save    = manager_save,
755 };
756
757 static gboolean nm_compat = FALSE;
758
759 int __connman_manager_init(DBusConnection *conn, gboolean compat)
760 {
761         DBG("conn %p", conn);
762
763         connection = dbus_connection_ref(conn);
764         if (connection == NULL)
765                 return -1;
766
767         if (connman_storage_register(&manager_storage) < 0)
768                 connman_error("Failed to register manager storage");
769
770         if (connman_notifier_register(&technology_notifier) < 0)
771                 connman_error("Failed to register technology notifier");
772
773         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
774                                         CONNMAN_MANAGER_INTERFACE,
775                                         manager_methods,
776                                         manager_signals, NULL, NULL, NULL);
777
778         if (compat == TRUE) {
779                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
780                                         nm_methods, NULL, NULL, NULL, NULL);
781
782                 nm_compat = TRUE;
783         }
784
785         return 0;
786 }
787
788 void __connman_manager_cleanup(void)
789 {
790         DBG("conn %p", connection);
791
792         connman_notifier_unregister(&technology_notifier);
793
794         connman_storage_unregister(&manager_storage);
795
796         if (nm_compat == TRUE) {
797                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
798         }
799
800         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
801                                                 CONNMAN_MANAGER_INTERFACE);
802
803         dbus_connection_unref(connection);
804 }