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