device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-glib / nm-client.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the
15  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301 USA.
17  *
18  * Copyright 2007 - 2008 Novell, Inc.
19  * Copyright 2007 - 2013 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-client.h"
25
26 #include <dbus/dbus-glib.h>
27 #include <string.h>
28
29 #include "nm-utils.h"
30
31 #include "nm-device-ethernet.h"
32 #include "nm-device-wifi.h"
33 #include "nm-device-private.h"
34 #include "nm-types-private.h"
35 #include "nm-object-private.h"
36 #include "nm-active-connection.h"
37 #include "nm-vpn-connection.h"
38 #include "nm-object-cache.h"
39 #include "nm-dbus-glib-types.h"
40
41 void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
42
43 static void nm_client_initable_iface_init (GInitableIface *iface);
44 static void nm_client_async_initable_iface_init (GAsyncInitableIface *iface);
45 static GInitableIface *nm_client_parent_initable_iface;
46 static GAsyncInitableIface *nm_client_parent_async_initable_iface;
47
48 G_DEFINE_TYPE_WITH_CODE (NMClient, nm_client, NM_TYPE_OBJECT,
49                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_client_initable_iface_init);
50                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, nm_client_async_initable_iface_init);
51                          )
52
53 #define NM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CLIENT, NMClientPrivate))
54
55 typedef struct {
56         DBusGProxy *client_proxy;
57         DBusGProxy *bus_proxy;
58         gboolean manager_running;
59         char *version;
60         NMState state;
61         gboolean startup;
62         GPtrArray *devices;
63         GPtrArray *all_devices;
64         GPtrArray *active_connections;
65         NMConnectivityState connectivity;
66         NMActiveConnection *primary_connection;
67         NMActiveConnection *activating_connection;
68
69         DBusGProxyCall *perm_call;
70         GHashTable *permissions;
71
72         /* Activations waiting for their NMActiveConnection
73          * to appear and then their callback to be called.
74          */
75         GSList *pending_activations;
76
77         gboolean networking_enabled;
78         gboolean wireless_enabled;
79         gboolean wireless_hw_enabled;
80
81         gboolean wwan_enabled;
82         gboolean wwan_hw_enabled;
83
84         gboolean wimax_enabled;
85         gboolean wimax_hw_enabled;
86 } NMClientPrivate;
87
88 enum {
89         PROP_0,
90         PROP_VERSION,
91         PROP_STATE,
92         PROP_STARTUP,
93         PROP_MANAGER_RUNNING,
94         PROP_NETWORKING_ENABLED,
95         PROP_WIRELESS_ENABLED,
96         PROP_WIRELESS_HARDWARE_ENABLED,
97         PROP_WWAN_ENABLED,
98         PROP_WWAN_HARDWARE_ENABLED,
99         PROP_WIMAX_ENABLED,
100         PROP_WIMAX_HARDWARE_ENABLED,
101         PROP_ACTIVE_CONNECTIONS,
102         PROP_CONNECTIVITY,
103         PROP_PRIMARY_CONNECTION,
104         PROP_ACTIVATING_CONNECTION,
105         PROP_DEVICES,
106         PROP_ALL_DEVICES,
107
108         LAST_PROP
109 };
110
111 enum {
112         DEVICE_ADDED,
113         DEVICE_REMOVED,
114         ANY_DEVICE_ADDED,
115         ANY_DEVICE_REMOVED,
116         PERMISSION_CHANGED,
117
118         LAST_SIGNAL
119 };
120
121 static guint signals[LAST_SIGNAL] = { 0 };
122
123 static void proxy_name_owner_changed (DBusGProxy *proxy,
124                                       const char *name,
125                                       const char *old_owner,
126                                       const char *new_owner,
127                                       gpointer user_data);
128
129 /**********************************************************************/
130
131 /**
132  * nm_client_error_quark:
133  *
134  * Registers an error quark for #NMClient if necessary.
135  *
136  * Returns: the error quark used for #NMClient errors.
137  *
138  * Since: 0.9.10
139  **/
140 GQuark
141 nm_client_error_quark (void)
142 {
143         static GQuark quark;
144
145         if (G_UNLIKELY (!quark))
146                 quark = g_quark_from_static_string ("nm-client-error-quark");
147         return quark;
148 }
149
150 /**********************************************************************/
151
152 static void
153 nm_client_init (NMClient *client)
154 {
155         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
156
157         priv->state = NM_STATE_UNKNOWN;
158
159         priv->permissions = g_hash_table_new (g_direct_hash, g_direct_equal);
160 }
161
162 static void
163 poke_wireless_devices_with_rf_status (NMClient *client)
164 {
165         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
166         int i;
167
168         for (i = 0; priv->all_devices && (i < priv->all_devices->len); i++) {
169                 NMDevice *device = g_ptr_array_index (priv->all_devices, i);
170
171                 if (NM_IS_DEVICE_WIFI (device))
172                         _nm_device_wifi_set_wireless_enabled (NM_DEVICE_WIFI (device), priv->wireless_enabled);
173         }
174 }
175
176 static void
177 wireless_enabled_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
178 {
179         poke_wireless_devices_with_rf_status (NM_CLIENT (object));
180 }
181
182 static void
183 register_properties (NMClient *client)
184 {
185         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
186         const NMPropertiesInfo property_info[] = {
187                 { NM_CLIENT_VERSION,                   &priv->version },
188                 { NM_CLIENT_STATE,                     &priv->state },
189                 { NM_CLIENT_STARTUP,                   &priv->startup },
190                 { NM_CLIENT_NETWORKING_ENABLED,        &priv->networking_enabled },
191                 { NM_CLIENT_WIRELESS_ENABLED,          &priv->wireless_enabled },
192                 { NM_CLIENT_WIRELESS_HARDWARE_ENABLED, &priv->wireless_hw_enabled },
193                 { NM_CLIENT_WWAN_ENABLED,              &priv->wwan_enabled },
194                 { NM_CLIENT_WWAN_HARDWARE_ENABLED,     &priv->wwan_hw_enabled },
195                 { NM_CLIENT_WIMAX_ENABLED,             &priv->wimax_enabled },
196                 { NM_CLIENT_WIMAX_HARDWARE_ENABLED,    &priv->wimax_hw_enabled },
197                 { NM_CLIENT_ACTIVE_CONNECTIONS,        &priv->active_connections, NULL, NM_TYPE_ACTIVE_CONNECTION },
198                 { NM_CLIENT_CONNECTIVITY,              &priv->connectivity },
199                 { NM_CLIENT_PRIMARY_CONNECTION,        &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
200                 { NM_CLIENT_ACTIVATING_CONNECTION,     &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
201                 { NM_CLIENT_DEVICES,                   &priv->devices, NULL, NM_TYPE_DEVICE, "device" },
202                 { NM_CLIENT_ALL_DEVICES,               &priv->all_devices, NULL, NM_TYPE_DEVICE, "any-device" },
203                 { NULL },
204         };
205
206         _nm_object_register_properties (NM_OBJECT (client),
207                                         priv->client_proxy,
208                                         property_info);
209 }
210
211 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
212 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI        "org.freedesktop.NetworkManager.enable-disable-wifi"
213 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN        "org.freedesktop.NetworkManager.enable-disable-wwan"
214 #define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX       "org.freedesktop.NetworkManager.enable-disable-wimax"
215 #define NM_AUTH_PERMISSION_SLEEP_WAKE                 "org.freedesktop.NetworkManager.sleep-wake"
216 #define NM_AUTH_PERMISSION_NETWORK_CONTROL            "org.freedesktop.NetworkManager.network-control"
217 #define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED       "org.freedesktop.NetworkManager.wifi.share.protected"
218 #define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN            "org.freedesktop.NetworkManager.wifi.share.open"
219 #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM     "org.freedesktop.NetworkManager.settings.modify.system"
220 #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN        "org.freedesktop.NetworkManager.settings.modify.own"
221 #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME   "org.freedesktop.NetworkManager.settings.modify.hostname"
222
223 static NMClientPermission
224 nm_permission_to_client (const char *nm)
225 {
226         if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK))
227                 return NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK;
228         else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI))
229                 return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI;
230         else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN))
231                 return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN;
232         else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX))
233                 return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX;
234         else if (!strcmp (nm, NM_AUTH_PERMISSION_SLEEP_WAKE))
235                 return NM_CLIENT_PERMISSION_SLEEP_WAKE;
236         else if (!strcmp (nm, NM_AUTH_PERMISSION_NETWORK_CONTROL))
237                 return NM_CLIENT_PERMISSION_NETWORK_CONTROL;
238         else if (!strcmp (nm, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED))
239                 return NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED;
240         else if (!strcmp (nm, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN))
241                 return NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN;
242         else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM))
243                 return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM;
244         else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN))
245                 return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN;
246         else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME))
247                 return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME;
248
249         return NM_CLIENT_PERMISSION_NONE;
250 }
251
252 static NMClientPermissionResult
253 nm_permission_result_to_client (const char *nm)
254 {
255         if (!strcmp (nm, "yes"))
256                 return NM_CLIENT_PERMISSION_RESULT_YES;
257         else if (!strcmp (nm, "no"))
258                 return NM_CLIENT_PERMISSION_RESULT_NO;
259         else if (!strcmp (nm, "auth"))
260                 return NM_CLIENT_PERMISSION_RESULT_AUTH;
261         return NM_CLIENT_PERMISSION_RESULT_UNKNOWN;
262 }
263
264 static void
265 update_permissions (NMClient *self, GHashTable *permissions)
266 {
267         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
268         GHashTableIter iter;
269         gpointer key, value;
270         NMClientPermission perm;
271         NMClientPermissionResult perm_result;
272         GList *keys, *keys_iter;
273
274         /* get list of old permissions for change notification */
275         keys = g_hash_table_get_keys (priv->permissions);
276         g_hash_table_remove_all (priv->permissions);
277
278         if (permissions) {
279                 /* Process new permissions */
280                 g_hash_table_iter_init (&iter, permissions);
281                 while (g_hash_table_iter_next (&iter, &key, &value)) {
282                         perm = nm_permission_to_client ((const char *) key);
283                         perm_result = nm_permission_result_to_client ((const char *) value);
284                         if (perm) {
285                                 g_hash_table_insert (priv->permissions,
286                                                      GUINT_TO_POINTER (perm),
287                                                      GUINT_TO_POINTER (perm_result));
288
289                                 /* Remove this permission from the list of previous permissions
290                                  * we'll be sending NM_CLIENT_PERMISSION_RESULT_UNKNOWN for
291                                  * in the change signal since it is still a known permission.
292                                  */
293                                 keys = g_list_remove (keys, GUINT_TO_POINTER (perm));
294                         }
295                 }
296         }
297
298         /* Signal changes in all updated permissions */
299         g_hash_table_iter_init (&iter, priv->permissions);
300         while (g_hash_table_iter_next (&iter, &key, &value)) {
301                 g_signal_emit (self, signals[PERMISSION_CHANGED], 0,
302                                GPOINTER_TO_UINT (key),
303                                GPOINTER_TO_UINT (value));
304         }
305
306         /* And signal changes in all permissions that used to be valid but for
307          * some reason weren't received in the last request (if any).
308          */
309         for (keys_iter = keys; keys_iter; keys_iter = g_list_next (keys_iter)) {
310                 g_signal_emit (self, signals[PERMISSION_CHANGED], 0,
311                                GPOINTER_TO_UINT (keys_iter->data),
312                                NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
313         }
314         g_list_free (keys);
315 }
316
317 static gboolean
318 get_permissions_sync (NMClient *self, GError **error)
319 {
320         gboolean success;
321         gs_unref_hashtable GHashTable *permissions = NULL;
322
323         success = dbus_g_proxy_call_with_timeout (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
324                                                   "GetPermissions", 3000, error,
325                                                   G_TYPE_INVALID,
326                                                   DBUS_TYPE_G_MAP_OF_STRING, &permissions, G_TYPE_INVALID);
327         update_permissions (self, success ? permissions : NULL);
328         return success;
329 }
330
331 static void
332 get_permissions_reply (DBusGProxy *proxy,
333                        DBusGProxyCall *call,
334                        gpointer user_data)
335 {
336         NMClient *self = NM_CLIENT (user_data);
337         gs_unref_hashtable GHashTable *permissions = NULL;
338         gs_free_error GError *error = NULL;
339
340         dbus_g_proxy_end_call (proxy, call, &error,
341                                DBUS_TYPE_G_MAP_OF_STRING, &permissions,
342                                G_TYPE_INVALID);
343         NM_CLIENT_GET_PRIVATE (self)->perm_call = NULL;
344         update_permissions (NM_CLIENT (user_data), error ? NULL : permissions);
345 }
346
347 static void
348 client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
349 {
350         NMClient *self = NM_CLIENT (user_data);
351         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
352
353         if (!priv->perm_call) {
354                 priv->perm_call = dbus_g_proxy_begin_call (NM_CLIENT_GET_PRIVATE (self)->client_proxy, "GetPermissions",
355                                                            get_permissions_reply, self, NULL,
356                                                            G_TYPE_INVALID);
357         }
358 }
359
360 /**
361  * nm_client_get_devices:
362  * @client: a #NMClient
363  *
364  * Gets all the known network devices.  Use nm_device_get_type() or the
365  * <literal>NM_IS_DEVICE_XXXX</literal> functions to determine what kind of
366  * device member of the returned array is, and then you may use device-specific
367  * methods such as nm_device_ethernet_get_hw_address().
368  *
369  * Returns: (transfer none) (element-type NMDevice): a #GPtrArray
370  * containing all the #NMDevices.  The returned array is owned by the
371  * #NMClient object and should not be modified.
372  **/
373 const GPtrArray *
374 nm_client_get_devices (NMClient *client)
375 {
376         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
377
378         _nm_object_ensure_inited (NM_OBJECT (client));
379
380         return handle_ptr_array_return (NM_CLIENT_GET_PRIVATE (client)->devices);
381 }
382
383 /**
384  * nm_client_get_all_devices:
385  * @client: a #NMClient
386  *
387  * Gets both real devices and device placeholders (eg, software devices which
388  * do not currently exist, but could be created automatically by NetworkManager
389  * if one of their NMDevice::ActivatableConnections was activated).  Use
390  * nm_device_is_real() to determine whether each device is a real device or
391  * a placeholder.
392  *
393  * Use nm_device_get_type() or the NM_IS_DEVICE_XXXX() functions to determine
394  * what kind of device each member of the returned array is, and then you may
395  * use device-specific methods such as nm_device_ethernet_get_hw_address().
396  *
397  * Returns: (transfer none) (element-type NMDevice): a #GPtrArray
398  * containing all the #NMDevices.  The returned array is owned by the
399  * #NMClient object and should not be modified.
400  *
401  * Since: 1.2
402  **/
403 const GPtrArray *
404 nm_client_get_all_devices (NMClient *client)
405 {
406         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
407
408         return NM_CLIENT_GET_PRIVATE (client)->all_devices;
409 }
410
411 /**
412  * nm_client_get_device_by_path:
413  * @client: a #NMClient
414  * @object_path: the object path to search for
415  *
416  * Gets a #NMDevice from a #NMClient.
417  *
418  * Returns: (transfer none): the #NMDevice for the given @object_path or %NULL if none is found.
419  **/
420 NMDevice *
421 nm_client_get_device_by_path (NMClient *client, const char *object_path)
422 {
423         const GPtrArray *devices;
424         int i;
425         NMDevice *device = NULL;
426
427         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
428         g_return_val_if_fail (object_path, NULL);
429
430         devices = nm_client_get_devices (client);
431         if (!devices)
432                 return NULL;
433
434         for (i = 0; i < devices->len; i++) {
435                 NMDevice *candidate = g_ptr_array_index (devices, i);
436                 if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), object_path)) {
437                         device = candidate;
438                         break;
439                 }
440         }
441
442         return device;
443 }
444
445 /**
446  * nm_client_get_device_by_iface:
447  * @client: a #NMClient
448  * @iface: the interface name to search for
449  *
450  * Gets a #NMDevice from a #NMClient.
451  *
452  * Returns: (transfer none): the #NMDevice for the given @iface or %NULL if none is found.
453  **/
454 NMDevice *
455 nm_client_get_device_by_iface (NMClient *client, const char *iface)
456 {
457         const GPtrArray *devices;
458         int i;
459         NMDevice *device = NULL;
460
461         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
462         g_return_val_if_fail (iface, NULL);
463
464         devices = nm_client_get_devices (client);
465         if (!devices)
466                 return NULL;
467
468         for (i = 0; i < devices->len; i++) {
469                 NMDevice *candidate = g_ptr_array_index (devices, i);
470                 if (!strcmp (nm_device_get_iface (candidate), iface)) {
471                         device = candidate;
472                         break;
473                 }
474         }
475
476         return device;
477 }
478
479 typedef struct {
480         NMClient *client;
481         NMClientActivateFn act_fn;
482         NMClientAddActivateFn add_act_fn;
483         char *active_path;
484         char *new_connection_path;
485         guint idle_id;
486         gpointer user_data;
487 } ActivateInfo;
488
489 static void
490 activate_info_free (ActivateInfo *info)
491 {
492         if (info->idle_id)
493                 g_source_remove (info->idle_id);
494         g_free (info->active_path);
495         g_free (info->new_connection_path);
496         memset (info, 0, sizeof (*info));
497         g_slice_free (ActivateInfo, info);
498 }
499
500 static void
501 activate_info_complete (ActivateInfo *info,
502                         NMActiveConnection *active,
503                         GError *error)
504 {
505         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (info->client);
506
507         if (info->act_fn)
508                 info->act_fn (info->client, error ? NULL : active, error, info->user_data);
509         else if (info->add_act_fn) {
510                 info->add_act_fn (info->client,
511                                   error ? NULL : active,
512                                   error ? NULL : info->new_connection_path,
513                                   error,
514                                   info->user_data);
515         } else if (error)
516                 g_warning ("Device activation failed: %s", error->message);
517
518         priv->pending_activations = g_slist_remove (priv->pending_activations, info);
519 }
520
521 static void
522 recheck_pending_activations (NMClient *self, const char *failed_path, GError *error)
523 {
524         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
525         GSList *iter, *next;
526         const GPtrArray *active_connections;
527         gboolean found_in_active = FALSE;
528         gboolean found_in_pending = FALSE;
529         ActivateInfo *ainfo = NULL;
530         int i;
531
532         active_connections = nm_client_get_active_connections (self);
533
534         /* For each pending activation, look for a active connection that has
535          * the pending activation's object path, and call pending connection's
536          * callback.
537          * If the connection to activate doesn't make it to active_connections,
538          * due to an error, we have to call the callback for failed_path.
539          */
540         for (iter = priv->pending_activations; iter; iter = next) {
541                 ActivateInfo *info = iter->data;
542
543                 next = g_slist_next (iter);
544
545                 if (!found_in_pending && failed_path && g_strcmp0 (failed_path, info->active_path) == 0) {
546                         found_in_pending = TRUE;
547                         ainfo = info;
548                 }
549
550                 for (i = 0; active_connections && i < active_connections->len; i++) {
551                         NMActiveConnection *active = g_ptr_array_index (active_connections, i);
552                         const char *active_path = nm_object_get_path (NM_OBJECT (active));
553
554                         if (!found_in_active && failed_path && g_strcmp0 (failed_path, active_path) == 0)
555                                 found_in_active = TRUE;
556
557                         if (g_strcmp0 (info->active_path, active_path) == 0) {
558                                 /* Call the pending activation's callback and it all up */
559                                 activate_info_complete (info, active, NULL);
560                                 activate_info_free (info);
561                                 break;
562                         }
563                 }
564         }
565
566         if (!found_in_active && found_in_pending) {
567                 /* A newly activated connection failed due to some immediate error
568                  * and disappeared from active connection list.  Make sure the
569                  * callback gets called.
570                  */
571                 activate_info_complete (ainfo, NULL, error);
572                 activate_info_free (ainfo);
573         }
574 }
575
576 static void
577 activate_cb (DBusGProxy *proxy,
578              DBusGProxyCall *call,
579              gpointer user_data)
580 {
581         ActivateInfo *info = user_data;
582         char *path;
583         GError *error = NULL;
584
585         dbus_g_proxy_end_call (proxy, call, &error,
586                                DBUS_TYPE_G_OBJECT_PATH, &path,
587                                G_TYPE_INVALID);
588         if (error) {
589                 activate_info_complete (info, NULL, error);
590                 activate_info_free (info);
591                 g_clear_error (&error);
592         } else {
593                 info->active_path = path;
594                 recheck_pending_activations (info->client, NULL, NULL);
595         }
596 }
597
598 static gboolean
599 activate_nm_not_running (gpointer user_data)
600 {
601         ActivateInfo *info = user_data;
602         GError *error;
603
604         info->idle_id = 0;
605
606         error = g_error_new_literal (NM_CLIENT_ERROR,
607                                      NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
608                                      "NetworkManager is not running");
609         activate_info_complete (info, NULL, error);
610         activate_info_free (info);
611         g_clear_error (&error);
612         return FALSE;
613 }
614
615 /**
616  * nm_client_activate_connection:
617  * @client: a #NMClient
618  * @connection: (allow-none): an #NMConnection
619  * @device: (allow-none): the #NMDevice
620  * @specific_object: (allow-none): the object path of a connection-type-specific
621  *   object this activation should use. This parameter is currently ignored for
622  *   wired and mobile broadband connections, and the value of %NULL should be used
623  *   (ie, no specific object).  For Wi-Fi or WiMAX connections, pass the object
624  *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
625  *   get using nm_object_get_path(), and which will be used to complete the
626  *   details of the newly added connection.
627  * @callback: (scope async) (allow-none): the function to call when the call is done
628  * @user_data: (closure): user data to pass to the callback function
629  *
630  * Starts a connection to a particular network using the configuration settings
631  * from @connection and the network device @device.  Certain connection types
632  * also take a "specific object" which is the object path of a connection-
633  * specific object, like an #NMAccessPoint for Wi-Fi connections, or an
634  * #NMWimaxNsp for WiMAX connections, to which you wish to connect.  If the
635  * specific object is not given, NetworkManager can, in some cases, automatically
636  * determine which network to connect to given the settings in @connection.
637  *
638  * If @connection is not given for a device-based activation, NetworkManager
639  * picks the best available connection for the device and activates it.
640  *
641  * Note that the callback is invoked when NetworkManager has started activating
642  * the new connection, not when it finishes. You can used the returned
643  * #NMActiveConnection object (in particular, #NMActiveConnection:state) to
644  * track the activation to its completion.
645  **/
646 void
647 nm_client_activate_connection (NMClient *client,
648                                NMConnection *connection,
649                                NMDevice *device,
650                                const char *specific_object,
651                                NMClientActivateFn callback,
652                                gpointer user_data)
653 {
654         NMClientPrivate *priv;
655         ActivateInfo *info;
656
657         g_return_if_fail (NM_IS_CLIENT (client));
658         if (device)
659                 g_return_if_fail (NM_IS_DEVICE (device));
660         if (connection)
661                 g_return_if_fail (NM_IS_CONNECTION (connection));
662
663         info = g_slice_new0 (ActivateInfo);
664         info->act_fn = callback;
665         info->user_data = user_data;
666         info->client = client;
667
668         priv = NM_CLIENT_GET_PRIVATE (client);
669         priv->pending_activations = g_slist_prepend (priv->pending_activations, info);
670
671         if (priv->manager_running == FALSE) {
672                 info->idle_id = g_idle_add (activate_nm_not_running, info);
673                 return;
674         }
675
676         dbus_g_proxy_begin_call (priv->client_proxy, "ActivateConnection",
677                                  activate_cb, info, NULL,
678                                  DBUS_TYPE_G_OBJECT_PATH, connection ? nm_connection_get_path (connection) : "/",
679                                  DBUS_TYPE_G_OBJECT_PATH, device ? nm_object_get_path (NM_OBJECT (device)) : "/",
680                                  DBUS_TYPE_G_OBJECT_PATH, specific_object ? specific_object : "/",
681                                  G_TYPE_INVALID);
682 }
683
684 static void
685 add_activate_cb (DBusGProxy *proxy,
686                  DBusGProxyCall *call,
687                  gpointer user_data)
688 {
689         ActivateInfo *info = user_data;
690         char *connection_path;
691         char *active_path;
692         GError *error = NULL;
693
694         dbus_g_proxy_end_call (proxy, call, &error,
695                                DBUS_TYPE_G_OBJECT_PATH, &connection_path,
696                                DBUS_TYPE_G_OBJECT_PATH, &active_path,
697                                G_TYPE_INVALID);
698         if (error) {
699                 activate_info_complete (info, NULL, error);
700                 activate_info_free (info);
701         } else {
702                 info->new_connection_path = connection_path;
703                 info->active_path = active_path;
704                 recheck_pending_activations (info->client, NULL, NULL);
705         }
706 }
707
708 /**
709  * nm_client_add_and_activate_connection:
710  * @client: a #NMClient
711  * @partial: (allow-none): an #NMConnection to add; the connection may be
712  *   partially filled (or even %NULL) and will be completed by NetworkManager
713  *   using the given @device and @specific_object before being added
714  * @device: the #NMDevice
715  * @specific_object: (allow-none): the object path of a connection-type-specific
716  *   object this activation should use. This parameter is currently ignored for
717  *   wired and mobile broadband connections, and the value of %NULL should be used
718  *   (ie, no specific object).  For Wi-Fi or WiMAX connections, pass the object
719  *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
720  *   get using nm_object_get_path(), and which will be used to complete the
721  *   details of the newly added connection.
722  * @callback: (scope async) (allow-none): the function to call when the call is done
723  * @user_data: (closure): user data to pass to the callback function
724  *
725  * Adds a new connection using the given details (if any) as a template,
726  * automatically filling in missing settings with the capabilities of the
727  * given device and specific object.  The new connection is then activated.
728  * Cannot be used for VPN connections at this time.
729  *
730  * Note that the callback is invoked when NetworkManager has started activating
731  * the new connection, not when it finishes. You can used the returned
732  * #NMActiveConnection object (in particular, #NMActiveConnection:state) to
733  * track the activation to its completion.
734  **/
735 void
736 nm_client_add_and_activate_connection (NMClient *client,
737                                        NMConnection *partial,
738                                        NMDevice *device,
739                                        const char *specific_object,
740                                        NMClientAddActivateFn callback,
741                                        gpointer user_data)
742 {
743         NMClientPrivate *priv;
744         ActivateInfo *info;
745         GHashTable *hash = NULL;
746
747         g_return_if_fail (NM_IS_CLIENT (client));
748         g_return_if_fail (NM_IS_DEVICE (device));
749
750         info = g_slice_new0 (ActivateInfo);
751         info->add_act_fn = callback;
752         info->user_data = user_data;
753         info->client = client;
754
755         if (partial)
756                 hash = nm_connection_to_hash (partial, NM_SETTING_HASH_FLAG_ALL);
757         if (!hash)
758                 hash = g_hash_table_new (g_str_hash, g_str_equal);
759
760         priv = NM_CLIENT_GET_PRIVATE (client);
761         priv->pending_activations = g_slist_prepend (priv->pending_activations, info);
762
763         if (priv->manager_running) {
764                 dbus_g_proxy_begin_call (priv->client_proxy, "AddAndActivateConnection",
765                                          add_activate_cb, info, NULL,
766                                          DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
767                                          DBUS_TYPE_G_OBJECT_PATH, nm_object_get_path (NM_OBJECT (device)),
768                                          DBUS_TYPE_G_OBJECT_PATH, specific_object ? specific_object : "/",
769                                          G_TYPE_INVALID);
770         } else
771                 info->idle_id = g_idle_add (activate_nm_not_running, info);
772
773         g_hash_table_unref (hash);
774 }
775
776 static void
777 active_connections_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
778 {
779         recheck_pending_activations (NM_CLIENT (object), NULL, NULL);
780 }
781
782 static void
783 object_creation_failed_cb (GObject *object, GError *error, char *failed_path)
784 {
785         if (error)
786                 recheck_pending_activations (NM_CLIENT (object), failed_path, error);
787 }
788
789 /**
790  * nm_client_deactivate_connection:
791  * @client: a #NMClient
792  * @active: the #NMActiveConnection to deactivate
793  *
794  * Deactivates an active #NMActiveConnection.
795  **/
796 void
797 nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active)
798 {
799         NMClientPrivate *priv;
800         const char *path;
801         GError *error = NULL;
802
803         g_return_if_fail (NM_IS_CLIENT (client));
804         g_return_if_fail (NM_IS_ACTIVE_CONNECTION (active));
805
806         priv = NM_CLIENT_GET_PRIVATE (client);
807         if (!priv->manager_running)
808                 return;
809
810         path = nm_object_get_path (NM_OBJECT (active));
811         if (!dbus_g_proxy_call (priv->client_proxy, "DeactivateConnection", &error,
812                                 DBUS_TYPE_G_OBJECT_PATH, path,
813                                 G_TYPE_INVALID,
814                                 G_TYPE_INVALID)) {
815                 g_warning ("Could not deactivate connection '%s': %s",
816                            path, NM_G_ERROR_MSG (error));
817                 g_clear_error (&error);
818         }
819 }
820
821 /**
822  * nm_client_get_active_connections:
823  * @client: a #NMClient
824  *
825  * Gets the active connections.
826  *
827  * Returns: (transfer none) (element-type NMActiveConnection): a #GPtrArray
828  *  containing all the active #NMActiveConnections.
829  * The returned array is owned by the client and should not be modified.
830  **/
831 const GPtrArray *
832 nm_client_get_active_connections (NMClient *client)
833 {
834         NMClientPrivate *priv;
835
836         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
837
838         _nm_object_ensure_inited (NM_OBJECT (client));
839
840         priv = NM_CLIENT_GET_PRIVATE (client);
841         if (!priv->manager_running)
842                 return NULL;
843
844         return handle_ptr_array_return (priv->active_connections);
845 }
846
847 /**
848  * nm_client_wireless_get_enabled:
849  * @client: a #NMClient
850  *
851  * Determines whether the wireless is enabled.
852  *
853  * Returns: %TRUE if wireless is enabled
854  **/
855 gboolean
856 nm_client_wireless_get_enabled (NMClient *client)
857 {
858         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
859
860         _nm_object_ensure_inited (NM_OBJECT (client));
861         return NM_CLIENT_GET_PRIVATE (client)->wireless_enabled;
862 }
863
864 /**
865  * nm_client_wireless_set_enabled:
866  * @client: a #NMClient
867  * @enabled: %TRUE to enable wireless
868  *
869  * Enables or disables wireless devices.
870  **/
871 void
872 nm_client_wireless_set_enabled (NMClient *client, gboolean enabled)
873 {
874         GValue value = G_VALUE_INIT;
875
876         g_return_if_fail (NM_IS_CLIENT (client));
877
878         if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
879                 return;
880
881         g_value_init (&value, G_TYPE_BOOLEAN);
882         g_value_set_boolean (&value, enabled);
883
884         _nm_object_set_property (NM_OBJECT (client),
885                                  NM_DBUS_INTERFACE,
886                                  "WirelessEnabled",
887                                  &value);
888 }
889
890 /**
891  * nm_client_wireless_hardware_get_enabled:
892  * @client: a #NMClient
893  *
894  * Determines whether the wireless hardware is enabled.
895  *
896  * Returns: %TRUE if the wireless hardware is enabled
897  **/
898 gboolean
899 nm_client_wireless_hardware_get_enabled (NMClient *client)
900 {
901         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
902
903         _nm_object_ensure_inited (NM_OBJECT (client));
904         return NM_CLIENT_GET_PRIVATE (client)->wireless_hw_enabled;
905 }
906
907 /**
908  * nm_client_wwan_get_enabled:
909  * @client: a #NMClient
910  *
911  * Determines whether WWAN is enabled.
912  *
913  * Returns: %TRUE if WWAN is enabled
914  **/
915 gboolean
916 nm_client_wwan_get_enabled (NMClient *client)
917 {
918         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
919
920         _nm_object_ensure_inited (NM_OBJECT (client));
921         return NM_CLIENT_GET_PRIVATE (client)->wwan_enabled;
922 }
923
924 /**
925  * nm_client_wwan_set_enabled:
926  * @client: a #NMClient
927  * @enabled: %TRUE to enable WWAN
928  *
929  * Enables or disables WWAN devices.
930  **/
931 void
932 nm_client_wwan_set_enabled (NMClient *client, gboolean enabled)
933 {
934         GValue value = G_VALUE_INIT;
935
936         g_return_if_fail (NM_IS_CLIENT (client));
937
938         if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
939                 return;
940
941         g_value_init (&value, G_TYPE_BOOLEAN);
942         g_value_set_boolean (&value, enabled);
943
944         _nm_object_set_property (NM_OBJECT (client),
945                                  NM_DBUS_INTERFACE,
946                                  "WwanEnabled",
947                                  &value);
948 }
949
950 /**
951  * nm_client_wwan_hardware_get_enabled:
952  * @client: a #NMClient
953  *
954  * Determines whether the WWAN hardware is enabled.
955  *
956  * Returns: %TRUE if the WWAN hardware is enabled
957  **/
958 gboolean
959 nm_client_wwan_hardware_get_enabled (NMClient *client)
960 {
961         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
962
963         _nm_object_ensure_inited (NM_OBJECT (client));
964         return NM_CLIENT_GET_PRIVATE (client)->wwan_hw_enabled;
965 }
966
967 /**
968  * nm_client_wimax_get_enabled:
969  * @client: a #NMClient
970  *
971  * Determines whether WiMAX is enabled.
972  *
973  * Returns: %TRUE if WiMAX is enabled
974  **/
975 gboolean
976 nm_client_wimax_get_enabled (NMClient *client)
977 {
978         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
979
980         _nm_object_ensure_inited (NM_OBJECT (client));
981         return NM_CLIENT_GET_PRIVATE (client)->wimax_enabled;
982 }
983
984 /**
985  * nm_client_wimax_set_enabled:
986  * @client: a #NMClient
987  * @enabled: %TRUE to enable WiMAX
988  *
989  * Enables or disables WiMAX devices.
990  **/
991 void
992 nm_client_wimax_set_enabled (NMClient *client, gboolean enabled)
993 {
994         GValue value = G_VALUE_INIT;
995
996         g_return_if_fail (NM_IS_CLIENT (client));
997
998         if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
999                 return;
1000
1001         g_value_init (&value, G_TYPE_BOOLEAN);
1002         g_value_set_boolean (&value, enabled);
1003
1004         _nm_object_set_property (NM_OBJECT (client),
1005                                  NM_DBUS_INTERFACE,
1006                                  "WimaxEnabled",
1007                                  &value);
1008 }
1009
1010 /**
1011  * nm_client_wimax_hardware_get_enabled:
1012  * @client: a #NMClient
1013  *
1014  * Determines whether the WiMAX hardware is enabled.
1015  *
1016  * Returns: %TRUE if the WiMAX hardware is enabled
1017  **/
1018 gboolean
1019 nm_client_wimax_hardware_get_enabled (NMClient *client)
1020 {
1021         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
1022
1023         _nm_object_ensure_inited (NM_OBJECT (client));
1024         return NM_CLIENT_GET_PRIVATE (client)->wimax_hw_enabled;
1025 }
1026
1027 /**
1028  * nm_client_get_version:
1029  * @client: a #NMClient
1030  *
1031  * Gets NetworkManager version.
1032  *
1033  * Returns: string with the version
1034  **/
1035 const char *
1036 nm_client_get_version (NMClient *client)
1037 {
1038         NMClientPrivate *priv;
1039
1040         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
1041
1042         priv = NM_CLIENT_GET_PRIVATE (client);
1043
1044         _nm_object_ensure_inited (NM_OBJECT (client));
1045
1046         return priv->manager_running ? priv->version : NULL;
1047 }
1048
1049 /**
1050  * nm_client_get_state:
1051  * @client: a #NMClient
1052  *
1053  * Gets the current daemon state.
1054  *
1055  * Returns: the current %NMState
1056  **/
1057 NMState
1058 nm_client_get_state (NMClient *client)
1059 {
1060         g_return_val_if_fail (NM_IS_CLIENT (client), NM_STATE_UNKNOWN);
1061
1062         _nm_object_ensure_inited (NM_OBJECT (client));
1063
1064         return NM_CLIENT_GET_PRIVATE (client)->state;
1065 }
1066
1067 /**
1068  * nm_client_get_startup:
1069  * @client: a #NMClient
1070  *
1071  * Tests whether the daemon is still in the process of activating
1072  * connections at startup.
1073  *
1074  * Returns: whether the daemon is still starting up
1075  *
1076  * Since: 0.9.10
1077  **/
1078 gboolean
1079 nm_client_get_startup (NMClient *client)
1080 {
1081         g_return_val_if_fail (NM_IS_CLIENT (client), NM_STATE_UNKNOWN);
1082
1083         _nm_object_ensure_inited (NM_OBJECT (client));
1084
1085         return NM_CLIENT_GET_PRIVATE (client)->startup;
1086 }
1087
1088 /**
1089  * nm_client_networking_get_enabled:
1090  * @client: a #NMClient
1091  *
1092  * Whether networking is enabled or disabled.
1093  *
1094  * Returns: %TRUE if networking is enabled, %FALSE if networking is disabled
1095  **/
1096 gboolean
1097 nm_client_networking_get_enabled (NMClient *client)
1098 {
1099         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
1100
1101         _nm_object_ensure_inited (NM_OBJECT (client));
1102         return NM_CLIENT_GET_PRIVATE (client)->networking_enabled;
1103 }
1104
1105 /**
1106  * nm_client_networking_set_enabled:
1107  * @client: a #NMClient
1108  * @enabled: %TRUE to set networking enabled, %FALSE to set networking disabled
1109  *
1110  * Enables or disables networking.  When networking is disabled, all controlled
1111  * interfaces are disconnected and deactivated.  When networking is enabled,
1112  * all controlled interfaces are available for activation.
1113  **/
1114 void
1115 nm_client_networking_set_enabled (NMClient *client, gboolean enable)
1116 {
1117         GError *err = NULL;
1118
1119         g_return_if_fail (NM_IS_CLIENT (client));
1120
1121         if (!NM_CLIENT_GET_PRIVATE (client)->manager_running)
1122                 return;
1123
1124         if (!dbus_g_proxy_call (NM_CLIENT_GET_PRIVATE (client)->client_proxy, "Enable", &err,
1125                                 G_TYPE_BOOLEAN, enable,
1126                                 G_TYPE_INVALID,
1127                                 G_TYPE_INVALID)) {
1128                 g_warning ("Error enabling/disabling networking: %s",
1129                            err ? err->message : "(unknown)");
1130                 g_clear_error (&err);
1131         }
1132 }
1133
1134 /**
1135  * nm_client_sleep:
1136  * @client: a #NMClient
1137  * @sleep_: %TRUE to put the daemon to sleep
1138  *
1139  * Deprecated; use nm_client_networking_set_enabled() instead.
1140  **/
1141 void
1142 nm_client_sleep (NMClient *client, gboolean sleep_)
1143 {
1144         nm_client_networking_set_enabled (client, !sleep_);
1145 }
1146
1147 /**
1148  * nm_client_get_manager_running:
1149  * @client: a #NMClient
1150  *
1151  * Determines whether the daemon is running.
1152  *
1153  * Returns: %TRUE if the daemon is running
1154  **/
1155 gboolean
1156 nm_client_get_manager_running (NMClient *client)
1157 {
1158         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
1159
1160         return NM_CLIENT_GET_PRIVATE (client)->manager_running;
1161 }
1162
1163 /**
1164  * nm_client_get_permission_result:
1165  * @client: a #NMClient
1166  * @permission: the permission for which to return the result, one of #NMClientPermission
1167  *
1168  * Requests the result of a specific permission, which indicates whether the
1169  * client can or cannot perform the action the permission represents
1170  *
1171  * Returns: the permission's result, one of #NMClientPermissionResult
1172  **/
1173 NMClientPermissionResult
1174 nm_client_get_permission_result (NMClient *client, NMClientPermission permission)
1175 {
1176         gpointer result;
1177
1178         g_return_val_if_fail (NM_IS_CLIENT (client), NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
1179
1180         result = g_hash_table_lookup (NM_CLIENT_GET_PRIVATE (client)->permissions,
1181                                       GUINT_TO_POINTER (permission));
1182         return GPOINTER_TO_UINT (result);
1183 }
1184
1185 /**
1186  * nm_client_get_logging:
1187  * @client: a #NMClient
1188  * @level: (allow-none): return location for logging level string
1189  * @domains: (allow-none): return location for log domains string. The string is
1190  *   a list of domains separated by ","
1191  * @error: (allow-none): return location for a #GError, or %NULL
1192  *
1193  * Gets NetworkManager current logging level and domains.
1194  *
1195  * Returns: %TRUE on success, %FALSE otherwise
1196  *
1197  * Since: 0.9.8
1198  **/
1199 gboolean
1200 nm_client_get_logging (NMClient *client, char **level, char **domains, GError **error)
1201 {
1202         NMClientPrivate *priv;
1203
1204         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
1205         g_return_val_if_fail (level == NULL || *level == NULL, FALSE);
1206         g_return_val_if_fail (domains == NULL || *domains == NULL, FALSE);
1207         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1208
1209         priv = NM_CLIENT_GET_PRIVATE (client);
1210         if (!priv->manager_running) {
1211                 g_set_error_literal (error,
1212                                      NM_CLIENT_ERROR,
1213                                      NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
1214                                      "NetworkManager is not running");
1215                 return FALSE;
1216         }
1217
1218         if (!level && !domains)
1219                 return TRUE;
1220
1221         return dbus_g_proxy_call (priv->client_proxy, "GetLogging", error,
1222                                   G_TYPE_INVALID,
1223                                   G_TYPE_STRING, level,
1224                                   G_TYPE_STRING, domains,
1225                                   G_TYPE_INVALID);
1226 }
1227
1228 /**
1229  * nm_client_set_logging:
1230  * @client: a #NMClient
1231  * @level: (allow-none): logging level to set (%NULL or an empty string for no change)
1232  * @domains: (allow-none): logging domains to set. The string should be a list of log
1233  *   domains separated by ",". (%NULL or an empty string for no change)
1234  * @error: (allow-none): return location for a #GError, or %NULL
1235  *
1236  * Sets NetworkManager logging level and/or domains.
1237  *
1238  * Returns: %TRUE on success, %FALSE otherwise
1239  *
1240  * Since: 0.9.8
1241  **/
1242 gboolean
1243 nm_client_set_logging (NMClient *client, const char *level, const char *domains, GError **error)
1244 {
1245         NMClientPrivate *priv;
1246
1247         g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
1248         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1249
1250         priv = NM_CLIENT_GET_PRIVATE (client);
1251         if (!priv->manager_running) {
1252                 g_set_error_literal (error,
1253                                      NM_CLIENT_ERROR,
1254                                      NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
1255                                      "NetworkManager is not running");
1256                 return FALSE;
1257         }
1258
1259         if (!level && !domains)
1260                 return TRUE;
1261
1262         return dbus_g_proxy_call (priv->client_proxy, "SetLogging", error,
1263                                   G_TYPE_STRING, level ? level : "",
1264                                   G_TYPE_STRING, domains ? domains : "",
1265                                   G_TYPE_INVALID,
1266                                   G_TYPE_INVALID);
1267 }
1268
1269 /**
1270  * nm_client_get_primary_connection:
1271  * @client: an #NMClient
1272  *
1273  * Gets the #NMActiveConnection corresponding to the primary active
1274  * network device.
1275  *
1276  * In particular, when there is no VPN active, or the VPN does not
1277  * have the default route, this returns the active connection that has
1278  * the default route. If there is a VPN active with the default route,
1279  * then this function returns the active connection that contains the
1280  * route to the VPN endpoint.
1281  *
1282  * If there is no default route, or the default route is over a
1283  * non-NetworkManager-recognized device, this will return %NULL.
1284  *
1285  * Returns: (transfer none): the appropriate #NMActiveConnection, if
1286  * any
1287  *
1288  * Since: 0.9.8.6
1289  */
1290 NMActiveConnection *
1291 nm_client_get_primary_connection (NMClient *client)
1292 {
1293         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
1294
1295         _nm_object_ensure_inited (NM_OBJECT (client));
1296         return NM_CLIENT_GET_PRIVATE (client)->primary_connection;
1297 }
1298
1299 /**
1300  * nm_client_get_activating_connection:
1301  * @client: an #NMClient
1302  *
1303  * Gets the #NMActiveConnection corresponding to a
1304  * currently-activating connection that is expected to become the new
1305  * #NMClient:primary-connection upon successful activation.
1306  *
1307  * Returns: (transfer none): the appropriate #NMActiveConnection, if
1308  * any.
1309  *
1310  * Since: 0.9.8.6
1311  */
1312 NMActiveConnection *
1313 nm_client_get_activating_connection (NMClient *client)
1314 {
1315         g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
1316
1317         _nm_object_ensure_inited (NM_OBJECT (client));
1318         return NM_CLIENT_GET_PRIVATE (client)->activating_connection;
1319 }
1320
1321 /****************************************************************/
1322
1323 static void
1324 free_devices (NMClient *client, gboolean in_dispose)
1325 {
1326         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
1327         gs_unref_ptrarray GPtrArray *real_devices = NULL;
1328         gs_unref_ptrarray GPtrArray *all_devices = NULL;
1329         GPtrArray *devices = NULL;
1330         guint i, j;
1331
1332         real_devices = priv->devices;
1333         all_devices = priv->all_devices;
1334
1335         if (in_dispose) {
1336                 priv->devices = NULL;
1337                 priv->all_devices = NULL;
1338         } else {
1339                 priv->devices = g_ptr_array_new ();
1340                 priv->all_devices = g_ptr_array_new ();
1341         }
1342
1343         if (all_devices && all_devices->len > 0)
1344                 devices = all_devices;
1345         else if (real_devices && real_devices->len > 0)
1346                 devices = real_devices;
1347
1348         if (real_devices && devices != real_devices) {
1349                 for (i = 0; i < real_devices->len; i++) {
1350                         NMDevice *d = real_devices->pdata[i];
1351
1352                         if (all_devices) {
1353                                 for (j = 0; j < all_devices->len; j++) {
1354                                         if (d == all_devices->pdata[j])
1355                                                 goto next;
1356                                 }
1357                         }
1358                         if (!in_dispose)
1359                                 g_signal_emit (client, signals[DEVICE_REMOVED], 0, d);
1360 next:
1361                         g_object_unref (d);
1362                 }
1363         }
1364         if (devices) {
1365                 for (i = 0; i < devices->len; i++) {
1366                         NMDevice *d = devices->pdata[i];
1367
1368                         if (!in_dispose)
1369                                 g_signal_emit (client, signals[DEVICE_REMOVED], 0, d);
1370                         g_object_unref (d);
1371                 }
1372         }
1373 }
1374
1375 static void
1376 free_active_connections (NMClient *client, gboolean emit_signals)
1377 {
1378         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
1379         GPtrArray *active_connections;
1380         NMActiveConnection *active_connection;
1381         int i;
1382
1383         if (!priv->active_connections)
1384                 return;
1385
1386         active_connections = priv->active_connections;
1387         priv->active_connections = NULL;
1388         for (i = 0; i < active_connections->len; i++) {
1389                 active_connection = active_connections->pdata[i];
1390                 /* Break circular refs */
1391                 g_object_run_dispose (G_OBJECT (active_connection));
1392                 g_object_unref (active_connection);
1393         }
1394         g_ptr_array_free (active_connections, TRUE);
1395
1396         if (emit_signals)
1397                 g_object_notify (G_OBJECT (client), NM_CLIENT_ACTIVE_CONNECTIONS);
1398 }
1399
1400 static void
1401 updated_properties (GObject *object, GAsyncResult *result, gpointer user_data)
1402 {
1403         NMClient *client = NM_CLIENT (user_data);
1404         GError *error = NULL;
1405
1406         if (!_nm_object_reload_properties_finish (NM_OBJECT (object), result, &error)) {
1407                 g_warning ("%s: error reading NMClient properties: %s", __func__, error->message);
1408                 g_error_free (error);
1409         }
1410
1411         _nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
1412 }
1413
1414 static void
1415 proxy_name_owner_changed (DBusGProxy *proxy,
1416                           const char *name,
1417                           const char *old_owner,
1418                           const char *new_owner,
1419                           gpointer user_data)
1420 {
1421         NMClient *client = NM_CLIENT (user_data);
1422         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
1423         gboolean old_good = (old_owner && strlen (old_owner));
1424         gboolean new_good = (new_owner && strlen (new_owner));
1425         gboolean new_running = FALSE;
1426
1427         if (!name || strcmp (name, NM_DBUS_SERVICE))
1428                 return;
1429
1430         if (!old_good && new_good)
1431                 new_running = TRUE;
1432         else if (old_good && !new_good)
1433                 new_running = FALSE;
1434
1435         if (new_running == priv->manager_running)
1436                 return;
1437
1438         priv->manager_running = new_running;
1439         if (!priv->manager_running) {
1440                 priv->state = NM_STATE_UNKNOWN;
1441                 priv->startup = FALSE;
1442                 _nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
1443                 _nm_object_suppress_property_updates (NM_OBJECT (client), TRUE);
1444                 poke_wireless_devices_with_rf_status (client);
1445                 free_devices (client, FALSE);
1446                 free_active_connections (client, TRUE);
1447                 update_permissions (client, NULL);
1448                 priv->wireless_enabled = FALSE;
1449                 priv->wireless_hw_enabled = FALSE;
1450                 priv->wwan_enabled = FALSE;
1451                 priv->wwan_hw_enabled = FALSE;
1452                 priv->wimax_enabled = FALSE;
1453                 priv->wimax_hw_enabled = FALSE;
1454                 g_free (priv->version);
1455                 priv->version = NULL;
1456
1457                 /* Clear object cache to ensure bad refcounting by clients doesn't
1458                  * keep objects in the cache.
1459                  */
1460                 _nm_object_cache_clear ();
1461         } else {
1462                 _nm_object_suppress_property_updates (NM_OBJECT (client), FALSE);
1463                 _nm_object_reload_properties_async (NM_OBJECT (client), updated_properties, client);
1464                 client_recheck_permissions (priv->client_proxy, client);
1465         }
1466 }
1467
1468 /**
1469  * nm_client_get_connectivity:
1470  * @client: an #NMClient
1471  *
1472  * Gets the current network connectivity state. Contrast
1473  * nm_client_check_connectivity() and
1474  * nm_client_check_connectivity_async(), which re-check the
1475  * connectivity state first before returning any information.
1476  *
1477  * Returns: the current connectivity state
1478  * Since: 0.9.8.6
1479  */
1480 NMConnectivityState
1481 nm_client_get_connectivity (NMClient *client)
1482 {
1483         NMClientPrivate *priv;
1484
1485         g_return_val_if_fail (NM_IS_CLIENT (client), NM_CONNECTIVITY_UNKNOWN);
1486         priv = NM_CLIENT_GET_PRIVATE (client);
1487
1488         _nm_object_ensure_inited (NM_OBJECT (client));
1489
1490         return priv->connectivity;
1491 }
1492
1493 /**
1494  * nm_client_check_connectivity:
1495  * @client: an #NMClient
1496  * @cancellable: a #GCancellable
1497  * @error: return location for a #GError
1498  *
1499  * Updates the network connectivity state and returns the (new)
1500  * current state. Contrast nm_client_get_connectivity(), which returns
1501  * the most recent known state without re-checking.
1502  *
1503  * This is a blocking call; use nm_client_check_connectivity_async()
1504  * if you do not want to block.
1505  *
1506  * Returns: the (new) current connectivity state
1507  * Since: 0.9.8.6
1508  */
1509 NMConnectivityState
1510 nm_client_check_connectivity (NMClient *client,
1511                               GCancellable *cancellable,
1512                               GError **error)
1513 {
1514         NMClientPrivate *priv;
1515         NMConnectivityState connectivity;
1516
1517         g_return_val_if_fail (NM_IS_CLIENT (client), NM_CONNECTIVITY_UNKNOWN);
1518         priv = NM_CLIENT_GET_PRIVATE (client);
1519
1520         if (!dbus_g_proxy_call (priv->client_proxy, "CheckConnectivity", error,
1521                                 G_TYPE_INVALID,
1522                                 G_TYPE_UINT, &connectivity,
1523                                 G_TYPE_INVALID))
1524                 connectivity = NM_CONNECTIVITY_UNKNOWN;
1525
1526         return connectivity;
1527 }
1528
1529 typedef struct {
1530         NMClient *client;
1531         DBusGProxyCall *call;
1532         GCancellable *cancellable;
1533         guint cancelled_id;
1534         NMConnectivityState connectivity;
1535 } CheckConnectivityData;
1536
1537 static void
1538 check_connectivity_data_free (CheckConnectivityData *ccd)
1539 {
1540         if (ccd->cancellable) {
1541                 if (ccd->cancelled_id)
1542                         g_signal_handler_disconnect (ccd->cancellable, ccd->cancelled_id);
1543                 g_object_unref (ccd->cancellable);
1544         }
1545
1546         g_slice_free (CheckConnectivityData, ccd);
1547 }
1548
1549 static void
1550 check_connectivity_cb (DBusGProxy *proxy,
1551                        DBusGProxyCall *call,
1552                        gpointer user_data)
1553 {
1554         GSimpleAsyncResult *simple = user_data;
1555         CheckConnectivityData *ccd = g_simple_async_result_get_op_res_gpointer (simple);
1556         GError *error = NULL;
1557
1558         if (ccd->cancellable) {
1559                 g_signal_handler_disconnect (ccd->cancellable, ccd->cancelled_id);
1560                 ccd->cancelled_id = 0;
1561         }
1562
1563         if (!dbus_g_proxy_end_call (proxy, call, &error,
1564                                     G_TYPE_UINT, &ccd->connectivity,
1565                                     G_TYPE_INVALID))
1566                 g_simple_async_result_take_error (simple, error);
1567
1568         g_simple_async_result_complete (simple);
1569         g_object_unref (simple);
1570 }
1571
1572 static void
1573 check_connectivity_cancelled_cb (GCancellable *cancellable,
1574                                  gpointer user_data)
1575 {
1576         GSimpleAsyncResult *simple = user_data;
1577         CheckConnectivityData *ccd = g_simple_async_result_get_op_res_gpointer (simple);
1578
1579         g_signal_handler_disconnect (cancellable, ccd->cancelled_id);
1580         ccd->cancelled_id = 0;
1581
1582         dbus_g_proxy_cancel_call (NM_CLIENT_GET_PRIVATE (ccd->client)->client_proxy, ccd->call);
1583         g_simple_async_result_complete_in_idle (simple);
1584 }
1585
1586 /**
1587  * nm_client_check_connectivity_async:
1588  * @client: an #NMClient
1589  * @cancellable: a #GCancellable
1590  * @callback: callback to call with the result
1591  * @user_data: data for @callback.
1592  *
1593  * Asynchronously updates the network connectivity state and invokes
1594  * @callback when complete. Contrast nm_client_get_connectivity(),
1595  * which (immediately) returns the most recent known state without
1596  * re-checking, and nm_client_check_connectivity(), which blocks.
1597  *
1598  * Since: 0.9.8.6
1599  */
1600 void
1601 nm_client_check_connectivity_async (NMClient *client,
1602                                     GCancellable *cancellable,
1603                                     GAsyncReadyCallback callback,
1604                                     gpointer user_data)
1605 {
1606         NMClientPrivate *priv;
1607         GSimpleAsyncResult *simple;
1608         CheckConnectivityData *ccd;
1609
1610         g_return_if_fail (NM_IS_CLIENT (client));
1611         priv = NM_CLIENT_GET_PRIVATE (client);
1612
1613         ccd = g_slice_new0 (CheckConnectivityData);
1614         ccd->client = client;
1615
1616         simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
1617                                             nm_client_check_connectivity_async);
1618         g_simple_async_result_set_op_res_gpointer (simple, ccd, (GDestroyNotify) check_connectivity_data_free);
1619
1620         if (cancellable) {
1621                 ccd->cancellable = g_object_ref (cancellable);
1622                 ccd->cancelled_id = g_signal_connect (cancellable, "cancelled",
1623                                                       G_CALLBACK (check_connectivity_cancelled_cb),
1624                                                       simple);
1625                 g_simple_async_result_set_check_cancellable (simple, cancellable);
1626         }
1627
1628         ccd->call = dbus_g_proxy_begin_call (priv->client_proxy, "CheckConnectivity",
1629                                              check_connectivity_cb, simple, NULL,
1630                                              G_TYPE_INVALID);
1631 }
1632
1633 /**
1634  * nm_client_check_connectivity_finish:
1635  * @client: an #NMClient
1636  * @result: the #GAsyncResult
1637  * @error: return location for a #GError
1638  *
1639  * Retrieves the result of an nm_client_check_connectivity_async()
1640  * call.
1641  *
1642  * Returns: the (new) current connectivity state
1643  * Since: 0.9.8.6
1644  */
1645 NMConnectivityState
1646 nm_client_check_connectivity_finish (NMClient *client,
1647                                      GAsyncResult *result,
1648                                      GError **error)
1649 {
1650         GSimpleAsyncResult *simple;
1651         CheckConnectivityData *ccd;
1652
1653         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), nm_client_check_connectivity_async), NM_CONNECTIVITY_UNKNOWN);
1654
1655         simple = G_SIMPLE_ASYNC_RESULT (result);
1656         ccd = g_simple_async_result_get_op_res_gpointer (simple);
1657
1658         if (g_simple_async_result_propagate_error (simple, error))
1659                 return NM_CONNECTIVITY_UNKNOWN;
1660
1661         return ccd->connectivity;
1662 }
1663
1664 /****************************************************************/
1665
1666 /**
1667  * nm_client_new:
1668  *
1669  * Creates a new #NMClient.
1670  *
1671  * Note that this will do blocking D-Bus calls to initialize the
1672  * client. You can use nm_client_new_async() if you want to avoid
1673  * that.
1674  *
1675  * NOTE: #NMClient provides information about devices and a mechanism to
1676  * control them.  To access and modify network configuration data, use the
1677  * #NMRemoteSettings object.
1678  *
1679  * Returns: a new #NMClient or NULL on an error
1680  **/
1681 NMClient *
1682 nm_client_new (void)
1683 {
1684         NMClient *client;
1685
1686         client = g_object_new (NM_TYPE_CLIENT, NM_OBJECT_DBUS_PATH, NM_DBUS_PATH, NULL);
1687
1688         /* NMObject's constructor() can fail on a D-Bus connection error. So we can
1689          * get NULL here instead of a valid NMClient object.
1690          */
1691         if (client)
1692                 _nm_object_ensure_inited (NM_OBJECT (client));
1693
1694         return client;
1695 }
1696
1697 static void
1698 client_inited (GObject *source, GAsyncResult *result, gpointer user_data)
1699 {
1700         GSimpleAsyncResult *simple = user_data;
1701         GError *error = NULL;
1702
1703         if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source), result, &error))
1704                 g_simple_async_result_take_error (simple, error);
1705         else
1706                 g_simple_async_result_set_op_res_gpointer (simple, source, g_object_unref);
1707         g_simple_async_result_complete (simple);
1708         g_object_unref (simple);
1709 }
1710
1711 /**
1712  * nm_client_new_async:
1713  * @cancellable: a #GCancellable, or %NULL
1714  * @callback: callback to call when the client is created
1715  * @user_data: data for @callback
1716  *
1717  * Creates a new #NMClient and begins asynchronously initializing it.
1718  * @callback will be called when it is done; use
1719  * nm_client_new_finish() to get the result. Note that on an error,
1720  * the callback can be invoked with two first parameters as NULL.
1721  *
1722  * NOTE: #NMClient provides information about devices and a mechanism to
1723  * control them.  To access and modify network configuration data, use the
1724  * #NMRemoteSettings object.
1725  **/
1726 void
1727 nm_client_new_async (GCancellable *cancellable,
1728                      GAsyncReadyCallback callback,
1729                      gpointer user_data)
1730 {
1731         NMClient *client;
1732         GSimpleAsyncResult *simple;
1733
1734         client = g_object_new (NM_TYPE_CLIENT, NM_OBJECT_DBUS_PATH, NM_DBUS_PATH, NULL);
1735         /* When client is NULL, do no continue with initialization and run callback
1736          * directly with result == NULL indicating NMClient creation failure.
1737          */
1738         if (!client) {
1739                 callback (NULL, NULL, user_data);
1740                 return;
1741         }
1742
1743         simple = g_simple_async_result_new (NULL, callback, user_data, nm_client_new_async);
1744         g_async_initable_init_async (G_ASYNC_INITABLE (client), G_PRIORITY_DEFAULT,
1745                                      cancellable, client_inited, simple);
1746 }
1747
1748 /**
1749  * nm_client_new_finish:
1750  * @result: a #GAsyncResult
1751  * @error: location for a #GError, or %NULL
1752  *
1753  * Gets the result of an nm_client_new_async() call.
1754  *
1755  * Returns: a new #NMClient, or %NULL on error
1756  **/
1757 NMClient *
1758 nm_client_new_finish (GAsyncResult *result, GError **error)
1759 {
1760         GSimpleAsyncResult *simple;
1761
1762         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1763
1764         if (!result) {
1765                 g_set_error_literal (error,
1766                                      NM_CLIENT_ERROR,
1767                                      NM_CLIENT_ERROR_UNKNOWN,
1768                                      "NMClient initialization failed (or you passed NULL 'result' by mistake)");
1769                 return NULL;
1770         }
1771
1772         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, nm_client_new_async), NULL);
1773
1774         simple = G_SIMPLE_ASYNC_RESULT (result);
1775         if (g_simple_async_result_propagate_error (simple, error))
1776                 return NULL;
1777         else
1778                 return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
1779 }
1780
1781 /*
1782  * constructor() shouldn't be overriden in most cases, rather constructed()
1783  * method is preferred and more useful.
1784  * But, this serves as a workaround for bindings (use) calling the constructor()
1785  * directly instead of nm_client_new() function, and neither providing
1786  * construction properties. So, we fill "dbus-path" here if it was not specified
1787  * (was set to default value (NULL)).
1788  *
1789  * It allows this python code:
1790  * from gi.repository import NMClient
1791  * nmclient = NMClient.Client()
1792  * print nmclient.get_active_connections()
1793  *
1794  * instead of proper
1795  * nmclient = NMClient.Client().new()
1796  *
1797  * Note:
1798  * A nice overview of GObject construction is here:
1799  * http://blogs.gnome.org/desrt/2012/02/26/a-gentle-introduction-to-gobject-construction
1800  * It is much better explanation than the official docs
1801  * http://developer.gnome.org/gobject/unstable/chapter-gobject.html#gobject-instantiation
1802  */
1803 static GObject*
1804 constructor (GType type,
1805              guint n_construct_params,
1806              GObjectConstructParam *construct_params)
1807 {
1808         GObject *object;
1809         guint i;
1810         const char *dbus_path;
1811
1812         for (i = 0; i < n_construct_params; i++) {
1813                 if (strcmp (construct_params[i].pspec->name, NM_OBJECT_DBUS_PATH) == 0) {
1814                         dbus_path = g_value_get_string (construct_params[i].value);
1815                         if (dbus_path == NULL) {
1816                                 g_value_set_static_string (construct_params[i].value, NM_DBUS_PATH);
1817                         } else {
1818                                 if (!g_variant_is_object_path (dbus_path)) {
1819                                         g_warning ("Passed D-Bus object path '%s' is invalid; using default '%s' instead",
1820                                                    dbus_path, NM_DBUS_PATH);
1821                                         g_value_set_static_string (construct_params[i].value, NM_DBUS_PATH);
1822                                 }
1823                         }
1824                         break;
1825                 }
1826         }
1827
1828         object = G_OBJECT_CLASS (nm_client_parent_class)->constructor (type,
1829                                                                        n_construct_params,
1830                                                                        construct_params);
1831
1832         return object;
1833 }
1834
1835 static void
1836 constructed (GObject *object)
1837 {
1838         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
1839         GError *error = NULL;
1840
1841         if (!nm_utils_init (&error)) {
1842                 g_warning ("Couldn't initilize nm-utils/crypto system: %s",
1843                            error->message);
1844                 g_clear_error (&error);
1845         }
1846
1847         G_OBJECT_CLASS (nm_client_parent_class)->constructed (object);
1848
1849         priv->client_proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE);
1850
1851         register_properties (NM_CLIENT (object));
1852
1853         /* Permissions */
1854         dbus_g_proxy_add_signal (priv->client_proxy, "CheckPermissions", G_TYPE_INVALID);
1855         dbus_g_proxy_connect_signal (priv->client_proxy,
1856                                      "CheckPermissions",
1857                                      G_CALLBACK (client_recheck_permissions),
1858                                      object,
1859                                      NULL);
1860
1861         priv->bus_proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
1862                                                      DBUS_SERVICE_DBUS,
1863                                                      DBUS_PATH_DBUS,
1864                                                      DBUS_INTERFACE_DBUS);
1865         g_assert (priv->bus_proxy);
1866
1867         dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged",
1868                                  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
1869                                  G_TYPE_INVALID);
1870         dbus_g_proxy_connect_signal (priv->bus_proxy,
1871                                      "NameOwnerChanged",
1872                                      G_CALLBACK (proxy_name_owner_changed),
1873                                      object, NULL);
1874
1875         g_signal_connect (object, "notify::" NM_CLIENT_WIRELESS_ENABLED,
1876                           G_CALLBACK (wireless_enabled_cb), NULL);
1877
1878         g_signal_connect (object, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
1879                           G_CALLBACK (active_connections_changed_cb), NULL);
1880
1881         g_signal_connect (object, "object-creation-failed",
1882                           G_CALLBACK (object_creation_failed_cb), NULL);
1883 }
1884
1885 static gboolean
1886 init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
1887 {
1888         NMClient *client = NM_CLIENT (initable);
1889         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
1890
1891         if (!nm_client_parent_initable_iface->init (initable, cancellable, error))
1892                 return FALSE;
1893
1894         if (!dbus_g_proxy_call (priv->bus_proxy,
1895                                 "NameHasOwner", error,
1896                                 G_TYPE_STRING, NM_DBUS_SERVICE,
1897                                 G_TYPE_INVALID,
1898                                 G_TYPE_BOOLEAN, &priv->manager_running,
1899                                 G_TYPE_INVALID))
1900                 return FALSE;
1901
1902         if (priv->manager_running && !get_permissions_sync (client, error))
1903                 return FALSE;
1904
1905         return TRUE;
1906 }
1907
1908 typedef struct {
1909         NMClient *client;
1910         GSimpleAsyncResult *result;
1911         gboolean properties_pending;
1912         gboolean permissions_pending;
1913 } NMClientInitData;
1914
1915 static void
1916 init_async_complete (NMClientInitData *init_data)
1917 {
1918         if (init_data->properties_pending || init_data->permissions_pending)
1919                 return;
1920
1921         g_simple_async_result_complete (init_data->result);
1922         g_object_unref (init_data->result);
1923         g_slice_free (NMClientInitData, init_data);
1924 }
1925
1926 static void
1927 init_async_got_permissions (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
1928 {
1929         NMClientInitData *init_data = user_data;
1930         gs_unref_hashtable GHashTable *permissions = NULL;
1931         gs_free_error GError *error = NULL;
1932
1933         dbus_g_proxy_end_call (proxy, call, &error,
1934                                DBUS_TYPE_G_MAP_OF_STRING, &permissions,
1935                                G_TYPE_INVALID);
1936         update_permissions (init_data->client, error ? NULL : permissions);
1937
1938         init_data->permissions_pending = FALSE;
1939         init_async_complete (init_data);
1940 }
1941
1942 static void
1943 init_async_got_properties (GObject *source, GAsyncResult *result, gpointer user_data)
1944 {
1945         NMClientInitData *init_data = user_data;
1946         GError *error = NULL;
1947
1948         if (!nm_client_parent_async_initable_iface->init_finish (G_ASYNC_INITABLE (source), result, &error))
1949                 g_simple_async_result_take_error (init_data->result, error);
1950
1951         init_data->properties_pending = FALSE;
1952         init_async_complete (init_data);
1953 }
1954
1955 static void
1956 finish_init (NMClientInitData *init_data)
1957 {
1958         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (init_data->client);
1959
1960         nm_client_parent_async_initable_iface->init_async (G_ASYNC_INITABLE (init_data->client),
1961                                                            G_PRIORITY_DEFAULT, NULL, /* FIXME cancellable */
1962                                                            init_async_got_properties, init_data);
1963         init_data->properties_pending = TRUE;
1964
1965         dbus_g_proxy_begin_call (priv->client_proxy, "GetPermissions",
1966                                  init_async_got_permissions, init_data, NULL,
1967                                  G_TYPE_INVALID);
1968         init_data->permissions_pending = TRUE;
1969 }
1970
1971 static void
1972 init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
1973                                 gpointer user_data)
1974 {
1975         NMClientInitData *init_data = user_data;
1976         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (init_data->client);
1977         GError *error = NULL;
1978
1979         if (!dbus_g_proxy_end_call (proxy, call, &error,
1980                                     G_TYPE_BOOLEAN, &priv->manager_running,
1981                                     G_TYPE_INVALID)) {
1982                 g_simple_async_result_take_error (init_data->result, error);
1983                 init_async_complete (init_data);
1984                 return;
1985         }
1986
1987         if (!priv->manager_running) {
1988                 init_async_complete (init_data);
1989                 return;
1990         }
1991
1992         finish_init (init_data);
1993 }
1994
1995 static void
1996 init_async (GAsyncInitable *initable, int io_priority,
1997             GCancellable *cancellable, GAsyncReadyCallback callback,
1998             gpointer user_data)
1999 {
2000         NMClientInitData *init_data;
2001         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (initable);
2002
2003         init_data = g_slice_new0 (NMClientInitData);
2004         init_data->client = NM_CLIENT (initable);
2005         init_data->result = g_simple_async_result_new (G_OBJECT (initable), callback,
2006                                                        user_data, init_async);
2007         g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
2008
2009         /* Check if NM is running */
2010         dbus_g_proxy_begin_call (priv->bus_proxy, "NameHasOwner",
2011                                  init_async_got_manager_running,
2012                                  init_data, NULL,
2013                                  G_TYPE_STRING, NM_DBUS_SERVICE,
2014                                  G_TYPE_INVALID);
2015 }
2016
2017 static gboolean
2018 init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error)
2019 {
2020         GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
2021
2022         if (g_simple_async_result_propagate_error (simple, error))
2023                 return FALSE;
2024         else
2025                 return TRUE;
2026 }
2027
2028 static void
2029 dispose (GObject *object)
2030 {
2031         NMClient *client = NM_CLIENT (object);
2032         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
2033
2034         if (priv->perm_call) {
2035                 dbus_g_proxy_cancel_call (priv->client_proxy, priv->perm_call);
2036                 priv->perm_call = NULL;
2037         }
2038
2039         g_clear_object (&priv->client_proxy);
2040         g_clear_object (&priv->bus_proxy);
2041
2042         free_devices (client, TRUE);
2043         free_active_connections (client, FALSE);
2044         g_clear_object (&priv->primary_connection);
2045         g_clear_object (&priv->activating_connection);
2046
2047         g_slist_free_full (priv->pending_activations, (GDestroyNotify) activate_info_free);
2048         priv->pending_activations = NULL;
2049
2050         g_hash_table_destroy (priv->permissions);
2051         priv->permissions = NULL;
2052
2053         G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
2054 }
2055
2056 static void
2057 finalize (GObject *object)
2058 {
2059         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
2060
2061         g_free (priv->version);
2062
2063         G_OBJECT_CLASS (nm_client_parent_class)->finalize (object);
2064 }
2065
2066 static void
2067 set_property (GObject *object, guint prop_id,
2068               const GValue *value, GParamSpec *pspec)
2069 {
2070         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
2071         gboolean b;
2072
2073         switch (prop_id) {
2074         case PROP_NETWORKING_ENABLED:
2075                 b = g_value_get_boolean (value);
2076                 if (priv->networking_enabled != b) {
2077                         nm_client_networking_set_enabled (NM_CLIENT (object), b);
2078                         /* Let the property value flip when we get the change signal from NM */
2079                 }
2080                 break;
2081         case PROP_WIRELESS_ENABLED:
2082                 b = g_value_get_boolean (value);
2083                 if (priv->wireless_enabled != b) {
2084                         nm_client_wireless_set_enabled (NM_CLIENT (object), b);
2085                         /* Let the property value flip when we get the change signal from NM */
2086                 }
2087                 break;
2088         case PROP_WWAN_ENABLED:
2089                 b = g_value_get_boolean (value);
2090                 if (priv->wwan_enabled != b) {
2091                         nm_client_wwan_set_enabled (NM_CLIENT (object), b);
2092                         /* Let the property value flip when we get the change signal from NM */
2093                 }
2094                 break;
2095         case PROP_WIMAX_ENABLED:
2096                 b = g_value_get_boolean (value);
2097                 if (priv->wimax_enabled != b) {
2098                         nm_client_wimax_set_enabled (NM_CLIENT (object), b);
2099                         /* Let the property value flip when we get the change signal from NM */
2100                 }
2101                 break;
2102         default:
2103                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2104                 break;
2105         }
2106 }
2107
2108 static void
2109 get_property (GObject *object,
2110               guint prop_id,
2111               GValue *value,
2112               GParamSpec *pspec)
2113 {
2114         NMClient *self = NM_CLIENT (object);
2115         NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
2116
2117         _nm_object_ensure_inited (NM_OBJECT (object));
2118
2119         switch (prop_id) {
2120         case PROP_VERSION:
2121                 g_value_set_string (value, nm_client_get_version (self));
2122                 break;
2123         case PROP_STATE:
2124                 g_value_set_uint (value, nm_client_get_state (self));
2125                 break;
2126         case PROP_STARTUP:
2127                 g_value_set_boolean (value, nm_client_get_startup (self));
2128                 break;
2129         case PROP_MANAGER_RUNNING:
2130                 g_value_set_boolean (value, priv->manager_running);
2131                 break;
2132         case PROP_NETWORKING_ENABLED:
2133                 g_value_set_boolean (value, nm_client_networking_get_enabled (self));
2134                 break;
2135         case PROP_WIRELESS_ENABLED:
2136                 g_value_set_boolean (value, priv->wireless_enabled);
2137                 break;
2138         case PROP_WIRELESS_HARDWARE_ENABLED:
2139                 g_value_set_boolean (value, priv->wireless_hw_enabled);
2140                 break;
2141         case PROP_WWAN_ENABLED:
2142                 g_value_set_boolean (value, priv->wwan_enabled);
2143                 break;
2144         case PROP_WWAN_HARDWARE_ENABLED:
2145                 g_value_set_boolean (value, priv->wwan_hw_enabled);
2146                 break;
2147         case PROP_WIMAX_ENABLED:
2148                 g_value_set_boolean (value, priv->wimax_enabled);
2149                 break;
2150         case PROP_WIMAX_HARDWARE_ENABLED:
2151                 g_value_set_boolean (value, priv->wimax_hw_enabled);
2152                 break;
2153         case PROP_ACTIVE_CONNECTIONS:
2154                 g_value_set_boxed (value, nm_client_get_active_connections (self));
2155                 break;
2156         case PROP_CONNECTIVITY:
2157                 g_value_set_uint (value, priv->connectivity);
2158                 break;
2159         case PROP_PRIMARY_CONNECTION:
2160                 g_value_set_object (value, priv->primary_connection);
2161                 break;
2162         case PROP_ACTIVATING_CONNECTION:
2163                 g_value_set_object (value, priv->activating_connection);
2164                 break;
2165         case PROP_DEVICES:
2166                 g_value_set_boxed (value, nm_client_get_devices (self));
2167                 break;
2168         case PROP_ALL_DEVICES:
2169                 g_value_set_boxed (value, nm_client_get_all_devices (self));
2170                 break;
2171         default:
2172                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2173                 break;
2174         }
2175 }
2176
2177 static void
2178 nm_client_class_init (NMClientClass *client_class)
2179 {
2180         GObjectClass *object_class = G_OBJECT_CLASS (client_class);
2181
2182         g_type_class_add_private (client_class, sizeof (NMClientPrivate));
2183
2184         /* virtual methods */
2185         object_class->constructor = constructor;
2186         object_class->constructed = constructed;
2187         object_class->set_property = set_property;
2188         object_class->get_property = get_property;
2189         object_class->dispose = dispose;
2190         object_class->finalize = finalize;
2191
2192         /* properties */
2193
2194         /**
2195          * NMClient:version:
2196          *
2197          * The NetworkManager version.
2198          **/
2199         g_object_class_install_property
2200                 (object_class, PROP_VERSION,
2201                  g_param_spec_string (NM_CLIENT_VERSION, "", "",
2202                                       NULL,
2203                                       G_PARAM_READABLE |
2204                                       G_PARAM_STATIC_STRINGS));
2205
2206         /**
2207          * NMClient:state:
2208          *
2209          * The current daemon state.
2210          **/
2211         g_object_class_install_property
2212                 (object_class, PROP_STATE,
2213                  g_param_spec_uint (NM_CLIENT_STATE, "", "",
2214                                     NM_STATE_UNKNOWN, NM_STATE_CONNECTED_GLOBAL, NM_STATE_UNKNOWN,
2215                                     G_PARAM_READABLE |
2216                                     G_PARAM_STATIC_STRINGS));
2217
2218         /**
2219          * NMClient:startup:
2220          *
2221          * Whether the daemon is still starting up.
2222          *
2223          * Since: 0.9.10
2224          **/
2225         g_object_class_install_property
2226                 (object_class, PROP_STARTUP,
2227                  g_param_spec_boolean (NM_CLIENT_STARTUP, "", "",
2228                                        FALSE,
2229                                        G_PARAM_READABLE |
2230                                        G_PARAM_STATIC_STRINGS));
2231
2232         /**
2233          * NMClient:manager-running:
2234          *
2235          * Whether the daemon is running.
2236          **/
2237         g_object_class_install_property
2238                 (object_class, PROP_MANAGER_RUNNING,
2239                  g_param_spec_boolean (NM_CLIENT_MANAGER_RUNNING, "", "",
2240                                        FALSE,
2241                                        G_PARAM_READABLE |
2242                                        G_PARAM_STATIC_STRINGS));
2243
2244         /**
2245          * NMClient:networking-enabled:
2246          *
2247          * Whether networking is enabled.
2248          **/
2249         g_object_class_install_property
2250                 (object_class, PROP_NETWORKING_ENABLED,
2251                  g_param_spec_boolean (NM_CLIENT_NETWORKING_ENABLED, "", "",
2252                                        TRUE,
2253                                        G_PARAM_READWRITE |
2254                                        G_PARAM_STATIC_STRINGS));
2255
2256         /**
2257          * NMClient:wireless-enabled:
2258          *
2259          * Whether wireless is enabled.
2260          **/
2261         g_object_class_install_property
2262                 (object_class, PROP_WIRELESS_ENABLED,
2263                  g_param_spec_boolean (NM_CLIENT_WIRELESS_ENABLED, "", "",
2264                                        FALSE,
2265                                        G_PARAM_READWRITE |
2266                                        G_PARAM_STATIC_STRINGS));
2267
2268         /**
2269          * NMClient:wireless-hardware-enabled:
2270          *
2271          * Whether the wireless hardware is enabled.
2272          **/
2273         g_object_class_install_property
2274                 (object_class, PROP_WIRELESS_HARDWARE_ENABLED,
2275                  g_param_spec_boolean (NM_CLIENT_WIRELESS_HARDWARE_ENABLED, "", "",
2276                                        TRUE,
2277                                        G_PARAM_READABLE |
2278                                        G_PARAM_STATIC_STRINGS));
2279
2280         /**
2281          * NMClient:wwan-enabled:
2282          *
2283          * Whether WWAN functionality is enabled.
2284          **/
2285         g_object_class_install_property
2286                 (object_class, PROP_WWAN_ENABLED,
2287                  g_param_spec_boolean (NM_CLIENT_WWAN_ENABLED, "", "",
2288                                        FALSE,
2289                                        G_PARAM_READWRITE |
2290                                        G_PARAM_STATIC_STRINGS));
2291
2292         /**
2293          * NMClient:wwan-hardware-enabled:
2294          *
2295          * Whether the WWAN hardware is enabled.
2296          **/
2297         g_object_class_install_property
2298                 (object_class, PROP_WWAN_HARDWARE_ENABLED,
2299                  g_param_spec_boolean (NM_CLIENT_WWAN_HARDWARE_ENABLED, "", "",
2300                                        FALSE,
2301                                        G_PARAM_READABLE |
2302                                        G_PARAM_STATIC_STRINGS));
2303
2304         /**
2305          * NMClient:wimax-enabled:
2306          *
2307          * Whether WiMAX functionality is enabled.
2308          **/
2309         g_object_class_install_property
2310                 (object_class, PROP_WIMAX_ENABLED,
2311                  g_param_spec_boolean (NM_CLIENT_WIMAX_ENABLED, "", "",
2312                                        FALSE,
2313                                        G_PARAM_READWRITE |
2314                                        G_PARAM_STATIC_STRINGS));
2315
2316         /**
2317          * NMClient:wimax-hardware-enabled:
2318          *
2319          * Whether the WiMAX hardware is enabled.
2320          **/
2321         g_object_class_install_property
2322                 (object_class, PROP_WIMAX_HARDWARE_ENABLED,
2323                  g_param_spec_boolean (NM_CLIENT_WIMAX_HARDWARE_ENABLED, "", "",
2324                                        FALSE,
2325                                        G_PARAM_READABLE |
2326                                        G_PARAM_STATIC_STRINGS));
2327
2328         /**
2329          * NMClient:active-connections:
2330          *
2331          * The active connections.
2332          * Type: GLib.PtrArray
2333          **/
2334         g_object_class_install_property
2335                 (object_class, PROP_ACTIVE_CONNECTIONS,
2336                  g_param_spec_boxed (NM_CLIENT_ACTIVE_CONNECTIONS, "", "",
2337                                      NM_TYPE_OBJECT_ARRAY,
2338                                      G_PARAM_READABLE |
2339                                      G_PARAM_STATIC_STRINGS));
2340
2341         /**
2342          * NMClient:connectivity:
2343          *
2344          * The network connectivity state.
2345          *
2346          * Since: 0.9.8.6
2347          */
2348         g_object_class_install_property
2349                 (object_class, PROP_CONNECTIVITY,
2350                  g_param_spec_uint (NM_CLIENT_CONNECTIVITY, "", "",
2351                                     NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
2352                                     G_PARAM_READABLE |
2353                                     G_PARAM_STATIC_STRINGS));
2354
2355         /**
2356          * NMClient:primary-connection:
2357          *
2358          * The #NMActiveConnection of the device with the default route;
2359          * see nm_client_get_primary_connection() for more details.
2360          *
2361          * Since: 0.9.8.6
2362          **/
2363         g_object_class_install_property
2364                 (object_class, PROP_PRIMARY_CONNECTION,
2365                  g_param_spec_object (NM_CLIENT_PRIMARY_CONNECTION, "", "",
2366                                       NM_TYPE_ACTIVE_CONNECTION,
2367                                       G_PARAM_READABLE |
2368                                       G_PARAM_STATIC_STRINGS));
2369
2370         /**
2371          * NMClient:activating-connection:
2372          *
2373          * The #NMActiveConnection of the activating connection that is
2374          * likely to become the new #NMClient:primary-connection.
2375          *
2376          * Since: 0.9.8.6
2377          **/
2378         g_object_class_install_property
2379                 (object_class, PROP_ACTIVATING_CONNECTION,
2380                  g_param_spec_object (NM_CLIENT_ACTIVATING_CONNECTION, "", "",
2381                                       NM_TYPE_ACTIVE_CONNECTION,
2382                                       G_PARAM_READABLE |
2383                                       G_PARAM_STATIC_STRINGS));
2384
2385         /**
2386          * NMClient:devices:
2387          *
2388          * List of real network devices.  Does not include placeholder devices.
2389          *
2390          * Since: 0.9.10
2391          **/
2392         g_object_class_install_property
2393                 (object_class, PROP_DEVICES,
2394                  g_param_spec_boxed (NM_CLIENT_DEVICES, "", "",
2395                                      NM_TYPE_OBJECT_ARRAY,
2396                                      G_PARAM_READABLE |
2397                                      G_PARAM_STATIC_STRINGS));
2398
2399         /**
2400          * NMClient:all-devices:
2401          *
2402          * List of both real devices and device placeholders.
2403          *
2404          * Since: 1.2
2405          **/
2406         g_object_class_install_property
2407                 (object_class, PROP_ALL_DEVICES,
2408                  g_param_spec_boxed (NM_CLIENT_ALL_DEVICES, "", "",
2409                                      NM_TYPE_OBJECT_ARRAY,
2410                                      G_PARAM_READABLE |
2411                                      G_PARAM_STATIC_STRINGS));
2412
2413         /* signals */
2414
2415         /**
2416          * NMClient::device-added:
2417          * @client: the client that received the signal
2418          * @device: (type NMDevice): the new device
2419          *
2420          * Notifies that a #NMDevice is added.  This signal is not emitted for
2421          * placeholder devices.
2422          **/
2423         signals[DEVICE_ADDED] =
2424                 g_signal_new ("device-added",
2425                               G_OBJECT_CLASS_TYPE (object_class),
2426                               G_SIGNAL_RUN_FIRST,
2427                               G_STRUCT_OFFSET (NMClientClass, device_added),
2428                               NULL, NULL, NULL,
2429                               G_TYPE_NONE, 1,
2430                               G_TYPE_OBJECT);
2431
2432         /**
2433          * NMClient::device-removed:
2434          * @client: the client that received the signal
2435          * @device: (type NMDevice): the removed device
2436          *
2437          * Notifies that a #NMDevice is removed.  This signal is not emitted for
2438          * placeholder devices.
2439          **/
2440         signals[DEVICE_REMOVED] =
2441                 g_signal_new ("device-removed",
2442                               G_OBJECT_CLASS_TYPE (object_class),
2443                               G_SIGNAL_RUN_FIRST,
2444                               G_STRUCT_OFFSET (NMClientClass, device_removed),
2445                               NULL, NULL, NULL,
2446                               G_TYPE_NONE, 1,
2447                               G_TYPE_OBJECT);
2448
2449         /**
2450          * NMClient::any-device-added:
2451          * @client: the client that received the signal
2452          * @device: (type NMDevice): the new device
2453          *
2454          * Notifies that a #NMDevice is added.  This signal is emitted for both
2455          * regular devices and placeholder devices.
2456          **/
2457         signals[ANY_DEVICE_ADDED] =
2458                 g_signal_new ("any-device-added",
2459                               G_OBJECT_CLASS_TYPE (object_class),
2460                               G_SIGNAL_RUN_FIRST,
2461                               0, NULL, NULL, NULL,
2462                               G_TYPE_NONE, 1,
2463                               G_TYPE_OBJECT);
2464
2465         /**
2466          * NMClient::any-device-removed:
2467          * @client: the client that received the signal
2468          * @device: (type NMDevice): the removed device
2469          *
2470          * Notifies that a #NMDevice is removed.  This signal is emitted for both
2471          * regular devices and placeholder devices.
2472          **/
2473         signals[ANY_DEVICE_REMOVED] =
2474                 g_signal_new ("any-device-removed",
2475                               G_OBJECT_CLASS_TYPE (object_class),
2476                               G_SIGNAL_RUN_FIRST,
2477                               0, NULL, NULL, NULL,
2478                               G_TYPE_NONE, 1,
2479                               G_TYPE_OBJECT);
2480
2481         /**
2482          * NMClient::permission-changed:
2483          * @client: the client that received the signal
2484          * @permission: a permission from #NMClientPermission
2485          * @result: the permission's result, one of #NMClientPermissionResult
2486          *
2487          * Notifies that a permission has changed
2488          **/
2489         signals[PERMISSION_CHANGED] =
2490                 g_signal_new ("permission-changed",
2491                               G_OBJECT_CLASS_TYPE (object_class),
2492                               G_SIGNAL_RUN_FIRST,
2493                               0, NULL, NULL, NULL,
2494                               G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
2495 }
2496
2497 static void
2498 nm_client_initable_iface_init (GInitableIface *iface)
2499 {
2500         nm_client_parent_initable_iface = g_type_interface_peek_parent (iface);
2501
2502         iface->init = init_sync;
2503 }
2504
2505 static void
2506 nm_client_async_initable_iface_init (GAsyncInitableIface *iface)
2507 {
2508         nm_client_parent_async_initable_iface = g_type_interface_peek_parent (iface);
2509
2510         iface->init_async = init_async;
2511         iface->init_finish = init_finish;
2512 }