libnm: be more accepting for invalid connections from NetworkManager
[NetworkManager.git] / libnm / nm-remote-connection.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 - 2011 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include <string.h>
25
26 #include "nm-dbus-interface.h"
27 #include "nm-utils.h"
28 #include "nm-setting-connection.h"
29 #include "nm-core-internal.h"
30
31 #include "nm-remote-connection.h"
32 #include "nm-remote-connection-private.h"
33 #include "nm-object-private.h"
34 #include "nm-dbus-helpers.h"
35
36 #include "nmdbus-settings-connection.h"
37
38 static void nm_remote_connection_connection_iface_init (NMConnectionInterface *iface);
39 static void nm_remote_connection_initable_iface_init (GInitableIface *iface);
40 static void nm_remote_connection_async_initable_iface_init (GAsyncInitableIface *iface);
41 static GInitableIface *nm_remote_connection_parent_initable_iface;
42 static GAsyncInitableIface *nm_remote_connection_parent_async_initable_iface;
43
44 G_DEFINE_TYPE_WITH_CODE (NMRemoteConnection, nm_remote_connection, NM_TYPE_OBJECT,
45                          G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION, nm_remote_connection_connection_iface_init);
46                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_remote_connection_initable_iface_init);
47                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, nm_remote_connection_async_initable_iface_init);
48                          )
49
50 enum {
51         PROP_0,
52         PROP_UNSAVED,
53         PROP_VISIBLE,
54
55         LAST_PROP
56 };
57
58 typedef struct {
59         NMDBusSettingsConnection *proxy;
60
61         gboolean unsaved;
62
63         gboolean visible;
64 } NMRemoteConnectionPrivate;
65
66 #define NM_REMOTE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_CONNECTION, NMRemoteConnectionPrivate))
67
68 /****************************************************************/
69
70 /**
71  * nm_remote_connection_commit_changes:
72  * @connection: the #NMRemoteConnection
73  * @save_to_disk: whether to persist the changes to disk
74  * @cancellable: a #GCancellable, or %NULL
75  * @error: location for a #GError, or %NULL
76  *
77  * Send any local changes to the settings and properties of @connection to
78  * NetworkManager. If @save_to_disk is %TRUE, the updated connection will be saved to
79  * disk; if %FALSE, then only the in-memory representation will be changed.
80  *
81  * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
82  **/
83 gboolean
84 nm_remote_connection_commit_changes (NMRemoteConnection *connection,
85                                      gboolean save_to_disk,
86                                      GCancellable *cancellable,
87                                      GError **error)
88 {
89         NMRemoteConnectionPrivate *priv;
90         GVariant *settings;
91         gboolean ret;
92
93         g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), FALSE);
94
95         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
96
97         settings = nm_connection_to_dbus (NM_CONNECTION (connection), NM_CONNECTION_SERIALIZE_ALL);
98         if (save_to_disk) {
99                 ret = nmdbus_settings_connection_call_update_sync (priv->proxy,
100                                                                    settings,
101                                                                    cancellable, error);
102         } else {
103                 ret = nmdbus_settings_connection_call_update_unsaved_sync (priv->proxy,
104                                                                            settings,
105                                                                            cancellable, error);
106         }
107         if (error && *error)
108                 g_dbus_error_strip_remote_error (*error);
109         return ret;
110 }
111
112 static void
113 update_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
114 {
115         GSimpleAsyncResult *simple = user_data;
116         gboolean (*finish_func) (NMDBusSettingsConnection *, GAsyncResult *, GError **);
117         GError *error = NULL;
118
119         finish_func = g_object_get_data (G_OBJECT (simple), "finish_func");
120         if (finish_func (NMDBUS_SETTINGS_CONNECTION (proxy), result, &error))
121                 g_simple_async_result_set_op_res_gboolean (simple, TRUE);
122         else {
123                 g_dbus_error_strip_remote_error (error);
124                 g_simple_async_result_take_error (simple, error);
125         }
126         g_simple_async_result_complete (simple);
127         g_object_unref (simple);
128 }
129
130 /**
131  * nm_remote_connection_commit_changes_async:
132  * @connection: the #NMRemoteConnection
133  * @save_to_disk: whether to save the changes to persistent storage
134  * @cancellable: a #GCancellable, or %NULL
135  * @callback: callback to be called when the commit operation completes
136  * @user_data: caller-specific data passed to @callback
137  *
138  * Asynchronously sends any local changes to the settings and properties of
139  * @connection to NetworkManager. If @save is %TRUE, the updated connection will
140  * be saved to disk; if %FALSE, then only the in-memory representation will be
141  * changed.
142  **/
143 void
144 nm_remote_connection_commit_changes_async (NMRemoteConnection *connection,
145                                            gboolean save_to_disk,
146                                            GCancellable *cancellable,
147                                            GAsyncReadyCallback callback,
148                                            gpointer user_data)
149 {
150         NMRemoteConnectionPrivate *priv;
151         GSimpleAsyncResult *simple;
152         GVariant *settings;
153
154         g_return_if_fail (NM_IS_REMOTE_CONNECTION (connection));
155
156         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
157
158         simple = g_simple_async_result_new (G_OBJECT (connection), callback, user_data,
159                                             nm_remote_connection_commit_changes_async);
160
161         settings = nm_connection_to_dbus (NM_CONNECTION (connection), NM_CONNECTION_SERIALIZE_ALL);
162         if (save_to_disk) {
163                 g_object_set_data (G_OBJECT (simple), "finish_func",
164                                    nmdbus_settings_connection_call_update_finish);
165                 nmdbus_settings_connection_call_update (priv->proxy,
166                                                         settings,
167                                                         cancellable,
168                                                         update_cb, simple);
169         } else {
170                 g_object_set_data (G_OBJECT (simple), "finish_func",
171                                    nmdbus_settings_connection_call_update_unsaved_finish);
172                 nmdbus_settings_connection_call_update_unsaved (priv->proxy,
173                                                                 settings,
174                                                                 cancellable,
175                                                                 update_cb, simple);
176         }
177 }
178
179 /**
180  * nm_remote_connection_commit_changes_finish:
181  * @connection: the #NMRemoteConnection
182  * @result: the result passed to the #GAsyncReadyCallback
183  * @error: location for a #GError, or %NULL
184  *
185  * Gets the result of a call to nm_remote_connection_commit_changes_async().
186  *
187  * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
188  **/
189 gboolean
190 nm_remote_connection_commit_changes_finish (NMRemoteConnection *connection,
191                                             GAsyncResult *result,
192                                             GError **error)
193 {
194         GSimpleAsyncResult *simple;
195
196         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (connection), nm_remote_connection_commit_changes_async), FALSE);
197
198         simple = G_SIMPLE_ASYNC_RESULT (result);
199         if (g_simple_async_result_propagate_error (simple, error))
200                 return FALSE;
201         else
202                 return g_simple_async_result_get_op_res_gboolean (simple);
203 }
204
205 /**
206  * nm_remote_connection_save:
207  * @connection: the #NMRemoteConnection
208  * @cancellable: a #GCancellable, or %NULL
209  * @error: location for a #GError, or %NULL
210  *
211  * Saves the connection to disk if the connection has changes that have not yet
212  * been written to disk, or if the connection has never been saved.
213  *
214  * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
215  **/
216 gboolean
217 nm_remote_connection_save (NMRemoteConnection *connection,
218                            GCancellable *cancellable,
219                            GError **error)
220 {
221         NMRemoteConnectionPrivate *priv;
222         gboolean ret;
223
224         g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), FALSE);
225
226         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
227
228         ret = nmdbus_settings_connection_call_save_sync (priv->proxy, cancellable, error);
229         if (error && *error)
230                 g_dbus_error_strip_remote_error (*error);
231         return ret;
232 }
233
234 static void
235 save_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
236 {
237         GSimpleAsyncResult *simple = user_data;
238         GError *error = NULL;
239
240         if (nmdbus_settings_connection_call_save_finish (NMDBUS_SETTINGS_CONNECTION (proxy),
241                                                          result, &error))
242                 g_simple_async_result_set_op_res_gboolean (simple, TRUE);
243         else {
244                 g_dbus_error_strip_remote_error (error);
245                 g_simple_async_result_take_error (simple, error);
246         }
247         g_simple_async_result_complete (simple);
248         g_object_unref (simple);
249 }
250
251 /**
252  * nm_remote_connection_save_async:
253  * @connection: the #NMRemoteConnection
254  * @cancellable: a #GCancellable, or %NULL
255  * @callback: callback to be called when the save operation completes
256  * @user_data: caller-specific data passed to @callback
257  *
258  * Saves the connection to disk if the connection has changes that have not yet
259  * been written to disk, or if the connection has never been saved.
260  **/
261 void
262 nm_remote_connection_save_async (NMRemoteConnection *connection,
263                                  GCancellable *cancellable,
264                                  GAsyncReadyCallback callback,
265                                  gpointer user_data)
266 {
267         NMRemoteConnectionPrivate *priv;
268         GSimpleAsyncResult *simple;
269
270         g_return_if_fail (NM_IS_REMOTE_CONNECTION (connection));
271
272         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
273
274         simple = g_simple_async_result_new (G_OBJECT (connection), callback, user_data,
275                                             nm_remote_connection_save_async);
276         nmdbus_settings_connection_call_save (priv->proxy, cancellable, save_cb, simple);
277 }
278
279 /**
280  * nm_remote_connection_save_finish:
281  * @connection: the #NMRemoteConnection
282  * @result: the result passed to the #GAsyncReadyCallback
283  * @error: location for a #GError, or %NULL
284  *
285  * Gets the result of a call to nm_remote_connection_save_async().
286  *
287  * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
288  **/
289 gboolean
290 nm_remote_connection_save_finish (NMRemoteConnection *connection,
291                                   GAsyncResult *result,
292                                   GError **error)
293 {
294         GSimpleAsyncResult *simple;
295
296         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (connection), nm_remote_connection_save_async), FALSE);
297
298         simple = G_SIMPLE_ASYNC_RESULT (result);
299         if (g_simple_async_result_propagate_error (simple, error))
300                 return FALSE;
301         else
302                 return g_simple_async_result_get_op_res_gboolean (simple);
303 }
304
305 /**
306  * nm_remote_connection_delete:
307  * @connection: the #NMRemoteConnection
308  * @cancellable: a #GCancellable, or %NULL
309  * @error: location for a #GError, or %NULL
310  *
311  * Deletes the connection.
312  *
313  * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
314  **/
315 gboolean
316 nm_remote_connection_delete (NMRemoteConnection *connection,
317                              GCancellable *cancellable,
318                              GError **error)
319 {
320         NMRemoteConnectionPrivate *priv;
321         gboolean ret;
322
323         g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), FALSE);
324
325         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
326
327         ret = nmdbus_settings_connection_call_delete_sync (priv->proxy, cancellable, error);
328         if (error && *error)
329                 g_dbus_error_strip_remote_error (*error);
330         return ret;
331 }
332
333 static void
334 delete_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
335 {
336         GSimpleAsyncResult *simple = user_data;
337         GError *error = NULL;
338
339         if (nmdbus_settings_connection_call_delete_finish (NMDBUS_SETTINGS_CONNECTION (proxy),
340                                                            result, &error))
341                 g_simple_async_result_set_op_res_gboolean (simple, TRUE);
342         else {
343                 g_dbus_error_strip_remote_error (error);
344                 g_simple_async_result_take_error (simple, error);
345         }
346         g_simple_async_result_complete (simple);
347         g_object_unref (simple);
348 }
349
350 /**
351  * nm_remote_connection_delete_async:
352  * @connection: the #NMRemoteConnection
353  * @cancellable: a #GCancellable, or %NULL
354  * @callback: callback to be called when the delete operation completes
355  * @user_data: caller-specific data passed to @callback
356  *
357  * Asynchronously deletes the connection.
358  **/
359 void
360 nm_remote_connection_delete_async (NMRemoteConnection *connection,
361                                    GCancellable *cancellable,
362                                    GAsyncReadyCallback callback,
363                                    gpointer user_data)
364 {
365         NMRemoteConnectionPrivate *priv;
366         GSimpleAsyncResult *simple;
367
368         g_return_if_fail (NM_IS_REMOTE_CONNECTION (connection));
369
370         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
371
372         simple = g_simple_async_result_new (G_OBJECT (connection), callback, user_data,
373                                             nm_remote_connection_delete_async);
374         nmdbus_settings_connection_call_delete (priv->proxy, cancellable, delete_cb, simple);
375 }
376
377 /**
378  * nm_remote_connection_delete_finish:
379  * @connection: the #NMRemoteConnection
380  * @result: the result passed to the #GAsyncReadyCallback
381  * @error: location for a #GError, or %NULL
382  *
383  * Gets the result of a call to nm_remote_connection_delete_async().
384  *
385  * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
386  **/
387 gboolean
388 nm_remote_connection_delete_finish (NMRemoteConnection *connection,
389                                     GAsyncResult *result,
390                                     GError **error)
391 {
392         GSimpleAsyncResult *simple;
393
394         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (connection), nm_remote_connection_delete_async), FALSE);
395
396         simple = G_SIMPLE_ASYNC_RESULT (result);
397         if (g_simple_async_result_propagate_error (simple, error))
398                 return FALSE;
399         else
400                 return g_simple_async_result_get_op_res_gboolean (simple);
401 }
402
403 /**
404  * nm_remote_connection_get_secrets:
405  * @connection: the #NMRemoteConnection
406  * @setting_name: the #NMSetting object name to get secrets for
407  * @cancellable: a #GCancellable, or %NULL
408  * @error: location for a #GError, or %NULL
409  *
410  * Request the connection's secrets. Note that this is a blocking D-Bus call,
411  * not a simple property accessor.
412  *
413  * Returns: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION containing
414  * @connection's secrets, or %NULL on error.
415  **/
416 GVariant *
417 nm_remote_connection_get_secrets (NMRemoteConnection *connection,
418                                   const char *setting_name,
419                                   GCancellable *cancellable,
420                                   GError **error)
421 {
422         NMRemoteConnectionPrivate *priv;
423         GVariant *secrets;
424
425         g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), NULL);
426
427         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
428
429         if (nmdbus_settings_connection_call_get_secrets_sync (priv->proxy,
430                                                               setting_name,
431                                                               &secrets,
432                                                               cancellable, error))
433                 return secrets;
434         else {
435                 if (error && *error)
436                         g_dbus_error_strip_remote_error (*error);
437                 return NULL;
438         }
439 }
440
441 static void
442 get_secrets_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
443 {
444         GSimpleAsyncResult *simple = user_data;
445         GVariant *secrets = NULL;
446         GError *error = NULL;
447
448         if (nmdbus_settings_connection_call_get_secrets_finish (NMDBUS_SETTINGS_CONNECTION (proxy),
449                                                                 &secrets, result, &error))
450                 g_simple_async_result_set_op_res_gpointer (simple, secrets, (GDestroyNotify) g_variant_unref);
451         else {
452                 g_dbus_error_strip_remote_error (error);
453                 g_simple_async_result_take_error (simple, error);
454         }
455
456         g_simple_async_result_complete (simple);
457         g_object_unref (simple);
458 }
459
460 /**
461  * nm_remote_connection_get_secrets_async:
462  * @connection: the #NMRemoteConnection
463  * @setting_name: the #NMSetting object name to get secrets for
464  * @cancellable: a #GCancellable, or %NULL
465  * @callback: callback to be called when the secret request completes
466  * @user_data: caller-specific data passed to @callback
467  *
468  * Asynchronously requests the connection's secrets.
469  **/
470 void
471 nm_remote_connection_get_secrets_async (NMRemoteConnection *connection,
472                                         const char *setting_name,
473                                         GCancellable *cancellable,
474                                         GAsyncReadyCallback callback,
475                                         gpointer user_data)
476 {
477         NMRemoteConnectionPrivate *priv;
478         GSimpleAsyncResult *simple;
479
480         g_return_if_fail (NM_IS_REMOTE_CONNECTION (connection));
481
482         priv = NM_REMOTE_CONNECTION_GET_PRIVATE (connection);
483
484         simple = g_simple_async_result_new (G_OBJECT (connection), callback, user_data,
485                                             nm_remote_connection_get_secrets_async);
486
487         nmdbus_settings_connection_call_get_secrets (priv->proxy,
488                                                      setting_name,
489                                                      cancellable,
490                                                      get_secrets_cb, simple);
491 }
492
493 /**
494  * nm_remote_connection_get_secrets_finish:
495  * @connection: the #NMRemoteConnection
496  * @result: the result passed to the #GAsyncReadyCallback
497  * @error: location for a #GError, or %NULL
498  *
499  * Gets the result of a call to nm_remote_connection_get_secrets_async().
500  *
501  * Returns: (transfer full): a #GVariant of type %NM_VARIANT_TYPE_CONNECTION
502  *   containing @connection's secrets, or %NULL on error.
503  **/
504 GVariant *
505 nm_remote_connection_get_secrets_finish (NMRemoteConnection *connection,
506                                          GAsyncResult *result,
507                                          GError **error)
508 {
509         GSimpleAsyncResult *simple;
510
511         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (connection), nm_remote_connection_get_secrets_async), FALSE);
512
513         simple = G_SIMPLE_ASYNC_RESULT (result);
514         if (g_simple_async_result_propagate_error (simple, error))
515                 return NULL;
516         else
517                 return g_variant_ref (g_simple_async_result_get_op_res_gpointer (simple));
518 }
519
520 /**
521  * nm_remote_connection_get_unsaved:
522  * @connection: the #NMRemoteConnection
523  *
524  * Returns: %TRUE if the remote connection contains changes that have not
525  * been saved to disk, %FALSE if the connection is the same as its on-disk
526  * representation.
527  **/
528 gboolean
529 nm_remote_connection_get_unsaved (NMRemoteConnection *connection)
530 {
531         g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), FALSE);
532
533         return NM_REMOTE_CONNECTION_GET_PRIVATE (connection)->unsaved;
534 }
535
536 /**
537  * nm_remote_connection_get_visible:
538  * @connection: the #NMRemoteConnection
539  *
540  * Checks if the connection is visible to the current user.  If the
541  * connection is not visible then it is essentially useless; it will
542  * not contain any settings, and operations such as
543  * nm_remote_connection_save() and nm_remote_connection_delete() will
544  * always fail. (#NMRemoteSettings will not normally return
545  * non-visible connections to callers, but it is possible for a
546  * connection's visibility to change after you already have a
547  * reference to it.)
548  *
549  * Returns: %TRUE if the remote connection is visible to the current
550  * user, %FALSE if not.
551  **/
552 gboolean
553 nm_remote_connection_get_visible (NMRemoteConnection *connection)
554 {
555         g_return_val_if_fail (NM_IS_REMOTE_CONNECTION (connection), FALSE);
556
557         return NM_REMOTE_CONNECTION_GET_PRIVATE (connection)->visible;
558 }
559
560 /****************************************************************/
561
562 static void
563 replace_settings (NMRemoteConnection *self, GVariant *new_settings)
564 {
565         GError *error = NULL;
566
567         if (!_nm_connection_replace_settings ((NMConnection *) self,
568                                               new_settings,
569                                               NM_SETTING_PARSE_FLAGS_BEST_EFFORT,
570                                               &error))
571                 g_clear_error (&error);
572 }
573
574 static void
575 updated_get_settings_cb (GObject *proxy,
576                          GAsyncResult *result,
577                          gpointer user_data)
578 {
579         NMRemoteConnection *self = user_data;
580         NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
581         GVariant *new_settings;
582         gboolean visible;
583
584         if (!nmdbus_settings_connection_call_get_settings_finish (priv->proxy, &new_settings,
585                                                                   result, NULL)) {
586                 /* Connection is no longer visible to this user. */
587                 nm_connection_clear_settings (NM_CONNECTION (self));
588
589                 visible = FALSE;
590         } else {
591                 replace_settings (self, new_settings);
592                 g_variant_unref (new_settings);
593
594                 visible = TRUE;
595         }
596
597         if (visible != priv->visible) {
598                 priv->visible = visible;
599                 g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_VISIBLE);
600         }
601
602         g_object_unref (self);
603 }
604
605 static void
606 updated_cb (NMDBusSettingsConnection *proxy, gpointer user_data)
607 {
608         NMRemoteConnection *self = NM_REMOTE_CONNECTION (user_data);
609         NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
610
611         /* The connection got updated; request the replacement settings */
612         nmdbus_settings_connection_call_get_settings (priv->proxy,
613                                                       NULL,
614                                                       updated_get_settings_cb,
615                                                       g_object_ref (self));
616 }
617
618 /****************************************************************/
619
620 static void
621 init_dbus (NMObject *object)
622 {
623         NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (object);
624         const NMPropertiesInfo property_info[] = {
625                 { NM_REMOTE_CONNECTION_UNSAVED, &priv->unsaved },
626                 { NULL },
627         };
628
629         NM_OBJECT_CLASS (nm_remote_connection_parent_class)->init_dbus (object);
630
631         priv->proxy = NMDBUS_SETTINGS_CONNECTION (_nm_object_get_proxy (object, NM_DBUS_INTERFACE_SETTINGS_CONNECTION));
632         g_assert (priv->proxy);
633
634         _nm_object_register_properties (object,
635                                         NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
636                                         property_info);
637
638         g_signal_connect (priv->proxy, "updated",
639                           G_CALLBACK (updated_cb), object);
640 }
641
642 static gboolean
643 init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
644 {
645         NMRemoteConnection *self = NM_REMOTE_CONNECTION (initable);
646         NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (initable);
647         GVariant *settings;
648
649         if (!nm_remote_connection_parent_initable_iface->init (initable, cancellable, error))
650                 return FALSE;
651
652         if (!nmdbus_settings_connection_call_get_settings_sync (priv->proxy,
653                                                                 &settings,
654                                                                 cancellable, error)) {
655                 if (error && *error)
656                         g_dbus_error_strip_remote_error (*error);
657                 return FALSE;
658         }
659
660         priv->visible = TRUE;
661         replace_settings (self, settings);
662         g_variant_unref (settings);
663
664         return TRUE;
665 }
666
667 typedef struct {
668         NMRemoteConnection *connection;
669         GCancellable *cancellable;
670         GSimpleAsyncResult *result;
671 } NMRemoteConnectionInitData;
672
673 static void
674 init_async_complete (NMRemoteConnectionInitData *init_data, GError *error)
675 {
676         if (error)
677                 g_simple_async_result_take_error (init_data->result, error);
678         else
679                 g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
680
681         g_simple_async_result_complete (init_data->result);
682         g_object_unref (init_data->result);
683         g_clear_object (&init_data->cancellable);
684         g_slice_free (NMRemoteConnectionInitData, init_data);
685 }
686
687 static void
688 init_get_settings_cb (GObject *proxy,
689                       GAsyncResult *result,
690                       gpointer user_data)
691 {
692         NMRemoteConnectionInitData *init_data = user_data;
693         NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (init_data->connection);
694         GVariant *settings;
695         GError *error = NULL;
696
697         if (!nmdbus_settings_connection_call_get_settings_finish (priv->proxy, &settings,
698                                                                   result, &error)) {
699                 g_dbus_error_strip_remote_error (error);
700                 init_async_complete (init_data, error);
701                 return;
702         }
703
704         priv->visible = TRUE;
705         replace_settings (init_data->connection, settings);
706         g_variant_unref (settings);
707
708         init_async_complete (init_data, NULL);
709 }
710
711 static void
712 init_async_parent_inited (GObject *source, GAsyncResult *result, gpointer user_data)
713 {
714         NMRemoteConnectionInitData *init_data = user_data;
715         NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (init_data->connection);
716         GError *error = NULL;
717
718         if (!nm_remote_connection_parent_async_initable_iface->init_finish (G_ASYNC_INITABLE (source), result, &error)) {
719                 init_async_complete (init_data, error);
720                 return;
721         }
722
723         nmdbus_settings_connection_call_get_settings (priv->proxy,
724                                                       init_data->cancellable,
725                                                       init_get_settings_cb, init_data);
726 }
727
728 static void
729 init_async (GAsyncInitable *initable, int io_priority,
730             GCancellable *cancellable, GAsyncReadyCallback callback,
731             gpointer user_data)
732 {
733         NMRemoteConnectionInitData *init_data;
734
735         init_data = g_slice_new0 (NMRemoteConnectionInitData);
736         init_data->connection = NM_REMOTE_CONNECTION (initable);
737         init_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
738         init_data->result = g_simple_async_result_new (G_OBJECT (initable), callback,
739                                                        user_data, init_async);
740
741         nm_remote_connection_parent_async_initable_iface->
742                 init_async (initable, io_priority, cancellable, init_async_parent_inited, init_data);
743 }
744
745 static gboolean
746 init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error)
747 {
748         GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
749
750         if (g_simple_async_result_propagate_error (simple, error))
751                 return FALSE;
752         else
753                 return TRUE;
754 }
755
756 static void
757 nm_remote_connection_init (NMRemoteConnection *self)
758 {
759 }
760
761 static void
762 get_property (GObject *object, guint prop_id,
763               GValue *value, GParamSpec *pspec)
764 {
765         switch (prop_id) {
766         case PROP_UNSAVED:
767                 g_value_set_boolean (value, NM_REMOTE_CONNECTION_GET_PRIVATE (object)->unsaved);
768                 break;
769         case PROP_VISIBLE:
770                 g_value_set_boolean (value, NM_REMOTE_CONNECTION_GET_PRIVATE (object)->visible);
771                 break;
772         default:
773                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
774                 break;
775         }
776 }
777
778 static void
779 constructed (GObject *object)
780 {
781         nm_connection_set_path (NM_CONNECTION (object),
782                                 nm_object_get_path (NM_OBJECT (object)));
783 }
784
785 static void
786 nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class)
787 {
788         GObjectClass *object_class = G_OBJECT_CLASS (remote_class);
789         NMObjectClass *nm_object_class = NM_OBJECT_CLASS (remote_class);
790
791         g_type_class_add_private (object_class, sizeof (NMRemoteConnectionPrivate));
792
793         _nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_SETTINGS_CONNECTION);
794         _nm_dbus_register_proxy_type (NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
795                                       NMDBUS_TYPE_SETTINGS_CONNECTION_PROXY);
796
797         /* virtual methods */
798         object_class->constructed = constructed;
799         object_class->get_property = get_property;
800
801         nm_object_class->init_dbus = init_dbus;
802
803         /* Properties */
804         /**
805          * NMRemoteConnection:unsaved:
806          *
807          * %TRUE if the remote connection contains changes that have not been saved
808          * to disk, %FALSE if the connection is the same as its on-disk representation.
809          **/
810         g_object_class_install_property
811                 (object_class, PROP_UNSAVED,
812                  g_param_spec_boolean (NM_REMOTE_CONNECTION_UNSAVED, "", "",
813                                        FALSE,
814                                        G_PARAM_READABLE |
815                                        G_PARAM_STATIC_STRINGS));
816
817         /**
818          * NMRemoteConnection:visible:
819          *
820          * %TRUE if the remote connection is visible to the current user, %FALSE if
821          * not.  If the connection is not visible then it is essentially useless; it
822          * will not contain any settings, and operations such as
823          * nm_remote_connection_save() and nm_remote_connection_delete() will always
824          * fail. (#NMRemoteSettings will not normally return non-visible connections
825          * to callers, but it is possible for a connection's visibility to change
826          * after you already have a reference to it.)
827          **/
828         g_object_class_install_property
829                 (object_class, PROP_VISIBLE,
830                  g_param_spec_boolean (NM_REMOTE_CONNECTION_VISIBLE, "", "",
831                                        FALSE,
832                                        G_PARAM_READABLE |
833                                        G_PARAM_STATIC_STRINGS));
834 }
835
836 static void
837 nm_remote_connection_connection_iface_init (NMConnectionInterface *iface)
838 {
839 }
840
841 static void
842 nm_remote_connection_initable_iface_init (GInitableIface *iface)
843 {
844         nm_remote_connection_parent_initable_iface = g_type_interface_peek_parent (iface);
845
846         iface->init = init_sync;
847 }
848
849 static void
850 nm_remote_connection_async_initable_iface_init (GAsyncInitableIface *iface)
851 {
852         nm_remote_connection_parent_async_initable_iface = g_type_interface_peek_parent (iface);
853
854         iface->init_async = init_async;
855         iface->init_finish = init_finish;
856 }