device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm / nm-remote-settings.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 2008 Novell, Inc.
19  * Copyright 2009 - 2012 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-remote-settings.h"
25
26 #include <string.h>
27
28 #include "nm-dbus-interface.h"
29 #include "nm-connection.h"
30
31 #include "nm-client.h"
32 #include "nm-remote-connection.h"
33 #include "nm-remote-connection-private.h"
34 #include "nm-object-private.h"
35 #include "nm-dbus-helpers.h"
36 #include "nm-object-private.h"
37 #include "nm-core-internal.h"
38
39 #include "nmdbus-settings.h"
40
41 G_DEFINE_TYPE (NMRemoteSettings, nm_remote_settings, NM_TYPE_OBJECT)
42
43 #define NM_REMOTE_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_REMOTE_SETTINGS, NMRemoteSettingsPrivate))
44
45 typedef struct {
46         NMDBusSettings *proxy;
47         GPtrArray *all_connections;
48         GPtrArray *visible_connections;
49         GCancellable *props_cancellable;
50
51         /* AddConnectionInfo objects that are waiting for the connection to become initialized */
52         GSList *add_list;
53
54         char *hostname;
55         gboolean can_modify;
56 } NMRemoteSettingsPrivate;
57
58 enum {
59         PROP_0,
60         PROP_CONNECTIONS,
61         PROP_HOSTNAME,
62         PROP_CAN_MODIFY,
63
64         LAST_PROP
65 };
66
67 /* Signals */
68 enum {
69         CONNECTION_ADDED,
70         CONNECTION_REMOVED,
71
72         LAST_SIGNAL
73 };
74 static guint signals[LAST_SIGNAL] = { 0 };
75
76 /**********************************************************************/
77
78 typedef struct {
79         NMRemoteSettings *self;
80         GSimpleAsyncResult *simple;
81         char *path;
82         gboolean saved;
83 } AddConnectionInfo;
84
85 static AddConnectionInfo *
86 add_connection_info_find (NMRemoteSettings *self, const char *path)
87 {
88         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
89         GSList *iter;
90
91         for (iter = priv->add_list; iter; iter = g_slist_next (iter)) {
92                 AddConnectionInfo *info = iter->data;
93
94                 if (!g_strcmp0 (info->path, path))
95                         return info;
96         }
97
98         return NULL;
99 }
100
101 static void
102 add_connection_info_complete (NMRemoteSettings *self,
103                               AddConnectionInfo *info,
104                               NMRemoteConnection *connection,
105                               GError *error)
106 {
107         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
108
109         g_return_if_fail (info != NULL);
110
111         if (connection) {
112                 g_simple_async_result_set_op_res_gpointer (info->simple,
113                                                            g_object_ref (connection),
114                                                            g_object_unref);
115         } else
116                 g_simple_async_result_set_from_error (info->simple, error);
117         g_simple_async_result_complete (info->simple);
118
119         g_object_unref (info->simple);
120         priv->add_list = g_slist_remove (priv->add_list, info);
121
122         g_free (info->path);
123         g_slice_free (AddConnectionInfo, info);
124 }
125
126 typedef const char * (*ConnectionStringGetter) (NMConnection *);
127
128 static NMRemoteConnection *
129 get_connection_by_string (NMRemoteSettings *settings,
130                           const char *string,
131                           ConnectionStringGetter get_comparison_string)
132 {
133         NMRemoteSettingsPrivate *priv;
134         NMConnection *candidate;
135         int i;
136
137         if (!_nm_object_get_nm_running (NM_OBJECT (settings)))
138                 return NULL;
139
140         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
141
142         for (i = 0; i < priv->visible_connections->len; i++) {
143                 candidate = priv->visible_connections->pdata[i];
144                 if (!g_strcmp0 (string, get_comparison_string (candidate)))
145                         return NM_REMOTE_CONNECTION (candidate);
146         }
147
148         return NULL;
149 }
150
151 NMRemoteConnection *
152 nm_remote_settings_get_connection_by_id (NMRemoteSettings *settings, const char *id)
153 {
154         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
155         g_return_val_if_fail (id != NULL, NULL);
156
157         return get_connection_by_string (settings, id, nm_connection_get_id);
158 }
159
160 NMRemoteConnection *
161 nm_remote_settings_get_connection_by_path (NMRemoteSettings *settings, const char *path)
162 {
163         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
164         g_return_val_if_fail (path != NULL, NULL);
165
166         return get_connection_by_string (settings, path, nm_connection_get_path);
167 }
168
169 NMRemoteConnection *
170 nm_remote_settings_get_connection_by_uuid (NMRemoteSettings *settings, const char *uuid)
171 {
172         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
173         g_return_val_if_fail (uuid != NULL, NULL);
174
175         return get_connection_by_string (settings, uuid, nm_connection_get_uuid);
176 }
177
178 static void
179 connection_visible_changed (GObject *object,
180                             GParamSpec *pspec,
181                             gpointer user_data)
182 {
183         NMRemoteConnection *connection = NM_REMOTE_CONNECTION (object);
184         NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data);
185
186         if (nm_remote_connection_get_visible (connection))
187                 g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection);
188         else
189                 g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection);
190 }
191
192 static void
193 cleanup_connection (NMRemoteSettings *self,
194                     NMRemoteConnection *remote)
195 {
196         g_signal_handlers_disconnect_by_func (remote, G_CALLBACK (connection_visible_changed), self);
197 }
198
199 static void
200 connection_removed (NMRemoteSettings *self,
201                     NMRemoteConnection *remote)
202 {
203         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
204         gboolean still_exists = FALSE;
205         int i;
206
207         /* Check if the connection was actually removed or if it just turned invisible. */
208         for (i = 0; i < priv->all_connections->len; i++) {
209                 if (remote == priv->all_connections->pdata[i]) {
210                         still_exists = TRUE;
211                         break;
212                 }
213         }
214
215         if (!still_exists)
216                 cleanup_connection (self, remote);
217
218         /* Allow the signal to propagate if and only if @remote was in visible_connections */
219         if (!g_ptr_array_remove (priv->visible_connections, remote))
220                 g_signal_stop_emission (self, signals[CONNECTION_REMOVED], 0);
221 }
222
223 static void
224 connection_added (NMRemoteSettings *self,
225                   NMRemoteConnection *remote)
226 {
227         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
228         AddConnectionInfo *addinfo;
229         const char *path;
230
231         if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL,
232                                     G_CALLBACK (connection_visible_changed), self)) {
233                 g_signal_connect (remote,
234                                   "notify::" NM_REMOTE_CONNECTION_VISIBLE,
235                                   G_CALLBACK (connection_visible_changed),
236                                   self);
237         }
238
239         if (nm_remote_connection_get_visible (remote))
240                 g_ptr_array_add (priv->visible_connections, remote);
241         else
242                 g_signal_stop_emission (self, signals[CONNECTION_ADDED], 0);
243
244         path = nm_connection_get_path (NM_CONNECTION (remote));
245         addinfo = add_connection_info_find (self, path);
246         if (addinfo)
247                 add_connection_info_complete (self, addinfo, remote, NULL);
248 }
249
250 static void
251 object_creation_failed (NMObject *object, const char *failed_path)
252 {
253         NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
254         AddConnectionInfo *addinfo;
255         GError *add_error;
256
257         addinfo = add_connection_info_find (self, failed_path);
258         if (addinfo) {
259                 add_error = g_error_new_literal (NM_CLIENT_ERROR,
260                                                  NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
261                                                  _("Connection removed before it was initialized"));
262                 add_connection_info_complete (self, addinfo, NULL, add_error);
263                 g_error_free (add_error);
264         }
265 }
266
267 const GPtrArray *
268 nm_remote_settings_get_connections (NMRemoteSettings *settings)
269 {
270         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
271
272         return NM_REMOTE_SETTINGS_GET_PRIVATE (settings)->visible_connections;
273 }
274
275 static void
276 add_connection_done (GObject *proxy, GAsyncResult *result, gpointer user_data)
277 {
278         AddConnectionInfo *info = user_data;
279         GError *error = NULL;
280
281         if (info->saved) {
282                 nmdbus_settings_call_add_connection_finish (NMDBUS_SETTINGS (proxy),
283                                                             &info->path,
284                                                             result, &error);
285         } else {
286                 nmdbus_settings_call_add_connection_unsaved_finish (NMDBUS_SETTINGS (proxy),
287                                                                     &info->path,
288                                                                     result, &error);
289         }
290
291         if (error) {
292                 g_dbus_error_strip_remote_error (error);
293                 add_connection_info_complete (info->self, info, NULL, error);
294                 g_clear_error (&error);
295         }
296
297         /* On success, we still have to wait until the connection is fully
298          * initialized before calling the callback.
299          */
300 }
301
302 void
303 nm_remote_settings_add_connection_async (NMRemoteSettings *settings,
304                                          NMConnection *connection,
305                                          gboolean save_to_disk,
306                                          GCancellable *cancellable,
307                                          GAsyncReadyCallback callback,
308                                          gpointer user_data)
309 {
310         NMRemoteSettingsPrivate *priv;
311         AddConnectionInfo *info;
312         GVariant *new_settings;
313
314         g_return_if_fail (NM_IS_REMOTE_SETTINGS (settings));
315         g_return_if_fail (NM_IS_CONNECTION (connection));
316
317         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
318
319         info = g_slice_new0 (AddConnectionInfo);
320         info->self = settings;
321         info->simple = g_simple_async_result_new (G_OBJECT (settings), callback, user_data,
322                                                   nm_remote_settings_add_connection_async);
323         info->saved = save_to_disk;
324
325         new_settings = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
326
327         if (save_to_disk) {
328                 nmdbus_settings_call_add_connection (priv->proxy,
329                                                      new_settings,
330                                                      NULL,
331                                                      add_connection_done, info);
332         } else {
333                 nmdbus_settings_call_add_connection_unsaved (priv->proxy,
334                                                              new_settings,
335                                                              NULL,
336                                                              add_connection_done, info);
337         }
338
339         priv->add_list = g_slist_append (priv->add_list, info);
340 }
341
342 NMRemoteConnection *
343 nm_remote_settings_add_connection_finish (NMRemoteSettings *settings,
344                                           GAsyncResult *result,
345                                           GError **error)
346 {
347         GSimpleAsyncResult *simple;
348
349         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (settings), nm_remote_settings_add_connection_async), NULL);
350
351         simple = G_SIMPLE_ASYNC_RESULT (result);
352         if (g_simple_async_result_propagate_error (simple, error))
353                 return NULL;
354         else
355                 return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
356 }
357
358 gboolean
359 nm_remote_settings_load_connections (NMRemoteSettings *settings,
360                                      char **filenames,
361                                      char ***failures,
362                                      GCancellable *cancellable,
363                                      GError **error)
364 {
365         NMRemoteSettingsPrivate *priv;
366         gboolean success;
367
368         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
369         g_return_val_if_fail (filenames != NULL, FALSE);
370
371         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
372
373         if (!nmdbus_settings_call_load_connections_sync (priv->proxy,
374                                                          (const char * const *) filenames,
375                                                          &success,
376                                                          failures,
377                                                          cancellable, error)) {
378                 if (error && *error)
379                         g_dbus_error_strip_remote_error (*error);
380                 success = FALSE;
381         }
382         return success;
383 }
384
385 static void
386 load_connections_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
387 {
388         GSimpleAsyncResult *simple = user_data;
389         GError *error = NULL;
390         gboolean success;
391         char **failures = NULL;
392
393         if (nmdbus_settings_call_load_connections_finish (NMDBUS_SETTINGS (proxy),
394                                                           &success, &failures,
395                                                           result, &error))
396                 g_simple_async_result_set_op_res_gpointer (simple, failures, (GDestroyNotify) g_strfreev);
397         else {
398                 g_dbus_error_strip_remote_error (error);
399                 g_simple_async_result_take_error (simple, error);
400         }
401
402         g_simple_async_result_complete (simple);
403         g_object_unref (simple);
404 }
405
406 void
407 nm_remote_settings_load_connections_async (NMRemoteSettings *settings,
408                                            char **filenames,
409                                            GCancellable *cancellable,
410                                            GAsyncReadyCallback callback,
411                                            gpointer user_data)
412 {
413         NMRemoteSettingsPrivate *priv;
414         GSimpleAsyncResult *simple;
415
416         g_return_if_fail (NM_IS_REMOTE_SETTINGS (settings));
417         g_return_if_fail (filenames != NULL);
418
419         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
420
421         simple = g_simple_async_result_new (G_OBJECT (settings), callback, user_data,
422                                             nm_remote_settings_load_connections_async);
423
424         nmdbus_settings_call_load_connections (priv->proxy,
425                                                (const char * const *) filenames,
426                                                cancellable, load_connections_cb, simple);
427 }
428
429 gboolean
430 nm_remote_settings_load_connections_finish (NMRemoteSettings *settings,
431                                             char ***failures,
432                                             GAsyncResult *result,
433                                             GError **error)
434 {
435         GSimpleAsyncResult *simple;
436
437         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (settings), nm_remote_settings_load_connections_async), FALSE);
438
439         simple = G_SIMPLE_ASYNC_RESULT (result);
440         if (g_simple_async_result_propagate_error (simple, error))
441                 return FALSE;
442         else {
443                 *failures = g_strdupv (g_simple_async_result_get_op_res_gpointer (simple));
444                 return TRUE;
445         }
446 }
447
448 gboolean
449 nm_remote_settings_reload_connections (NMRemoteSettings *settings,
450                                        GCancellable *cancellable,
451                                        GError **error)
452 {
453         NMRemoteSettingsPrivate *priv;
454         gboolean success;
455
456         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
457
458         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
459
460         if (!nmdbus_settings_call_reload_connections_sync (priv->proxy, &success,
461                                                            cancellable, error)) {
462                 if (error && *error)
463                         g_dbus_error_strip_remote_error (*error);
464                 success = FALSE;
465         }
466
467         return success;
468 }
469
470 static void
471 reload_connections_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
472 {
473         GSimpleAsyncResult *simple = user_data;
474         gboolean success;
475         GError *error = NULL;
476
477         if (nmdbus_settings_call_reload_connections_finish (NMDBUS_SETTINGS (proxy),
478                                                             &success,
479                                                             result, &error))
480                 g_simple_async_result_set_op_res_gboolean (simple, success);
481         else {
482                 g_dbus_error_strip_remote_error (error);
483                 g_simple_async_result_take_error (simple, error);
484         }
485
486         g_simple_async_result_complete (simple);
487         g_object_unref (simple);
488 }
489
490 void
491 nm_remote_settings_reload_connections_async (NMRemoteSettings *settings,
492                                              GCancellable *cancellable,
493                                              GAsyncReadyCallback callback,
494                                              gpointer user_data)
495 {
496         NMRemoteSettingsPrivate *priv;
497         GSimpleAsyncResult *simple;
498
499         g_return_if_fail (NM_IS_REMOTE_SETTINGS (settings));
500
501         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
502
503         simple = g_simple_async_result_new (G_OBJECT (settings), callback, user_data,
504                                             nm_remote_settings_reload_connections_async);
505
506         nmdbus_settings_call_reload_connections (priv->proxy, cancellable,
507                                                  reload_connections_cb, simple);
508 }
509
510 gboolean
511 nm_remote_settings_reload_connections_finish (NMRemoteSettings *settings,
512                                               GAsyncResult *result,
513                                               GError **error)
514 {
515         GSimpleAsyncResult *simple;
516
517         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (settings), nm_remote_settings_reload_connections_async), FALSE);
518
519         simple = G_SIMPLE_ASYNC_RESULT (result);
520         if (g_simple_async_result_propagate_error (simple, error))
521                 return FALSE;
522         else
523                 return g_simple_async_result_get_op_res_gboolean (simple);
524 }
525
526 gboolean
527 nm_remote_settings_save_hostname (NMRemoteSettings *settings,
528                                   const char *hostname,
529                                   GCancellable *cancellable,
530                                   GError **error)
531 {
532         NMRemoteSettingsPrivate *priv;
533         gboolean ret;
534
535
536         g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
537
538         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
539
540         ret = nmdbus_settings_call_save_hostname_sync (priv->proxy,
541                                                        hostname ? hostname : "",
542                                                        cancellable, error);
543         if (error && *error)
544                 g_dbus_error_strip_remote_error (*error);
545         return ret;
546 }
547
548 static void
549 save_hostname_cb (GObject *proxy,
550                   GAsyncResult *result,
551                   gpointer user_data)
552 {
553         GSimpleAsyncResult *simple = user_data;
554         GError *error = NULL;
555
556         if (nmdbus_settings_call_save_hostname_finish (NMDBUS_SETTINGS (proxy), result, &error))
557                 g_simple_async_result_set_op_res_gboolean (simple, TRUE);
558         else {
559                 g_dbus_error_strip_remote_error (error);
560                 g_simple_async_result_take_error (simple, error);
561         }
562         g_simple_async_result_complete (simple);
563         g_object_unref (simple);
564 }
565
566 void
567 nm_remote_settings_save_hostname_async (NMRemoteSettings *settings,
568                                         const char *hostname,
569                                         GCancellable *cancellable,
570                                         GAsyncReadyCallback callback,
571                                         gpointer user_data)
572 {
573         NMRemoteSettingsPrivate *priv;
574         GSimpleAsyncResult *simple;
575
576         g_return_if_fail (NM_IS_REMOTE_SETTINGS (settings));
577
578         priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
579
580         simple = g_simple_async_result_new (G_OBJECT (settings), callback, user_data,
581                                             nm_remote_settings_save_hostname_async);
582
583         nmdbus_settings_call_save_hostname (priv->proxy,
584                                             hostname ? hostname : "",
585                                             cancellable, save_hostname_cb, simple);
586 }
587
588 gboolean
589 nm_remote_settings_save_hostname_finish (NMRemoteSettings *settings,
590                                          GAsyncResult *result,
591                                          GError **error)
592 {
593         GSimpleAsyncResult *simple;
594
595         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (settings), nm_remote_settings_save_hostname_async), FALSE);
596
597         simple = G_SIMPLE_ASYNC_RESULT (result);
598         if (g_simple_async_result_propagate_error (simple, error))
599                 return FALSE;
600         else
601                 return g_simple_async_result_get_op_res_gboolean (simple);
602 }
603
604 static void
605 updated_properties (GObject *object, GAsyncResult *result, gpointer user_data)
606 {
607         GError *error = NULL;
608
609         if (!_nm_object_reload_properties_finish (NM_OBJECT (object), result, &error)) {
610                 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
611                         g_warning ("%s: error reading NMRemoteSettings properties: %s", __func__, error->message);
612                 g_error_free (error);
613         }
614 }
615
616 static void
617 nm_running_changed (GObject *object,
618                     GParamSpec *pspec,
619                     gpointer user_data)
620 {
621         NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
622         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
623
624         g_object_freeze_notify (object);
625
626         if (!_nm_object_get_nm_running (NM_OBJECT (self))) {
627                 GPtrArray *connections;
628                 int i;
629
630                 nm_clear_g_cancellable (&priv->props_cancellable);
631
632                 /* Clear connections */
633                 connections = priv->all_connections;
634                 priv->all_connections = g_ptr_array_new ();
635                 for (i = 0; i < connections->len; i++)
636                         g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connections->pdata[i]);
637                 g_ptr_array_unref (connections);
638
639                 /* Clear properties */
640                 if (priv->hostname) {
641                         g_free (priv->hostname);
642                         priv->hostname = NULL;
643                         g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_HOSTNAME);
644                 }
645
646                 if (priv->can_modify) {
647                         priv->can_modify = FALSE;
648                         g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_CAN_MODIFY);
649                 }
650
651                 _nm_object_suppress_property_updates (NM_OBJECT (self), TRUE);
652         } else {
653                 _nm_object_suppress_property_updates (NM_OBJECT (self), FALSE);
654
655                 nm_clear_g_cancellable (&priv->props_cancellable);
656                 priv->props_cancellable = g_cancellable_new ();
657                 _nm_object_reload_properties_async (NM_OBJECT (self), priv->props_cancellable, updated_properties, self);
658         }
659
660         g_object_thaw_notify (object);
661 }
662
663 /****************************************************************/
664
665 static void
666 nm_remote_settings_init (NMRemoteSettings *self)
667 {
668         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
669
670         priv->all_connections = g_ptr_array_new ();
671         priv->visible_connections = g_ptr_array_new ();
672 }
673
674 static void
675 init_dbus (NMObject *object)
676 {
677         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object);
678         const NMPropertiesInfo property_info[] = {
679                 { NM_REMOTE_SETTINGS_CONNECTIONS,      &priv->all_connections, NULL, NM_TYPE_REMOTE_CONNECTION, "connection" },
680                 { NM_REMOTE_SETTINGS_HOSTNAME,         &priv->hostname },
681                 { NM_REMOTE_SETTINGS_CAN_MODIFY,       &priv->can_modify },
682                 { NULL },
683         };
684
685         NM_OBJECT_CLASS (nm_remote_settings_parent_class)->init_dbus (object);
686
687         priv->proxy = NMDBUS_SETTINGS (_nm_object_get_proxy (object, NM_DBUS_INTERFACE_SETTINGS));
688         _nm_object_register_properties (object,
689                                         NM_DBUS_INTERFACE_SETTINGS,
690                                         property_info);
691
692         g_signal_connect (object, "notify::" NM_OBJECT_NM_RUNNING,
693                           G_CALLBACK (nm_running_changed), object);
694 }
695
696 static GObject *
697 constructor (GType type,
698              guint n_construct_params,
699              GObjectConstructParam *construct_params)
700 {
701         guint i;
702         const char *dbus_path;
703
704         /* Fill in the right D-Bus path if none was specified */
705         for (i = 0; i < n_construct_params; i++) {
706                 if (strcmp (construct_params[i].pspec->name, NM_OBJECT_PATH) == 0) {
707                         dbus_path = g_value_get_string (construct_params[i].value);
708                         if (dbus_path == NULL) {
709                                 g_value_set_static_string (construct_params[i].value, NM_DBUS_PATH_SETTINGS);
710                         } else {
711                                 if (!g_variant_is_object_path (dbus_path)) {
712                                         g_warning ("Passed D-Bus object path '%s' is invalid; using default '%s' instead",
713                                                    dbus_path, NM_DBUS_PATH);
714                                         g_value_set_static_string (construct_params[i].value, NM_DBUS_PATH_SETTINGS);
715                                 }
716                         }
717                         break;
718                 }
719         }
720
721         return G_OBJECT_CLASS (nm_remote_settings_parent_class)->constructor (type,
722                                                                               n_construct_params,
723                                                                               construct_params);
724 }
725
726 static void
727 dispose (GObject *object)
728 {
729         NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
730         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
731         int i;
732
733         if (priv->all_connections) {
734                 for (i = 0; i < priv->all_connections->len; i++)
735                         cleanup_connection (self, priv->all_connections->pdata[i]);
736                 g_clear_pointer (&priv->all_connections, g_ptr_array_unref);
737         }
738
739         g_signal_handlers_disconnect_by_func (object, G_CALLBACK (nm_running_changed), self);
740
741         g_clear_pointer (&priv->visible_connections, g_ptr_array_unref);
742         g_clear_pointer (&priv->hostname, g_free);
743
744         G_OBJECT_CLASS (nm_remote_settings_parent_class)->dispose (object);
745 }
746
747 static void
748 get_property (GObject *object, guint prop_id,
749               GValue *value, GParamSpec *pspec)
750 {
751         NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object);
752
753         switch (prop_id) {
754         case PROP_CONNECTIONS:
755                 g_value_take_boxed (value, _nm_utils_copy_object_array (priv->visible_connections));
756                 break;
757         case PROP_HOSTNAME:
758                 g_value_set_string (value, priv->hostname);
759                 break;
760         case PROP_CAN_MODIFY:
761                 g_value_set_boolean (value, priv->can_modify);
762                 break;
763         default:
764                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
765                 break;
766         }
767 }
768
769 static void
770 nm_remote_settings_class_init (NMRemoteSettingsClass *class)
771 {
772         GObjectClass *object_class = G_OBJECT_CLASS (class);
773         NMObjectClass *nm_object_class = NM_OBJECT_CLASS (class);
774
775         g_type_class_add_private (class, sizeof (NMRemoteSettingsPrivate));
776
777         _nm_object_class_add_interface (nm_object_class, NM_DBUS_INTERFACE_SETTINGS);
778         _nm_dbus_register_proxy_type (NM_DBUS_INTERFACE_SETTINGS, NMDBUS_TYPE_SETTINGS_PROXY);
779
780         /* Virtual methods */
781         object_class->constructor = constructor;
782         object_class->get_property = get_property;
783         object_class->dispose = dispose;
784
785         nm_object_class->init_dbus = init_dbus;
786         nm_object_class->object_creation_failed = object_creation_failed;
787
788         class->connection_added = connection_added;
789         class->connection_removed = connection_removed;
790
791         /* Properties */
792
793         g_object_class_install_property
794                 (object_class, PROP_CONNECTIONS,
795                  g_param_spec_boxed (NM_REMOTE_SETTINGS_CONNECTIONS, "", "",
796                                      G_TYPE_PTR_ARRAY,
797                                      G_PARAM_READABLE |
798                                      G_PARAM_STATIC_STRINGS));
799
800         g_object_class_install_property
801                 (object_class, PROP_HOSTNAME,
802                  g_param_spec_string (NM_REMOTE_SETTINGS_HOSTNAME, "", "",
803                                       NULL,
804                                       G_PARAM_READABLE |
805                                       G_PARAM_STATIC_STRINGS));
806
807         g_object_class_install_property
808                 (object_class, PROP_CAN_MODIFY,
809                  g_param_spec_boolean (NM_REMOTE_SETTINGS_CAN_MODIFY, "", "",
810                                        FALSE,
811                                        G_PARAM_READABLE |
812                                        G_PARAM_STATIC_STRINGS));
813
814         /* Signals */
815         signals[CONNECTION_ADDED] =
816                 g_signal_new (NM_REMOTE_SETTINGS_CONNECTION_ADDED,
817                               G_OBJECT_CLASS_TYPE (object_class),
818                               G_SIGNAL_RUN_FIRST,
819                               G_STRUCT_OFFSET (NMRemoteSettingsClass, connection_added),
820                               NULL, NULL, NULL,
821                               G_TYPE_NONE, 1,
822                               NM_TYPE_REMOTE_CONNECTION);
823
824         signals[CONNECTION_REMOVED] =
825                 g_signal_new (NM_REMOTE_SETTINGS_CONNECTION_REMOVED,
826                               G_OBJECT_CLASS_TYPE (object_class),
827                               G_SIGNAL_RUN_FIRST,
828                               G_STRUCT_OFFSET (NMRemoteSettingsClass, connection_removed),
829                               NULL, NULL, NULL,
830                               G_TYPE_NONE, 1,
831                               NM_TYPE_REMOTE_CONNECTION);
832 }