Imported Upstream version 2.66.6
[platform/upstream/glib.git] / gio / gdbusobjectmanagerserver.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include "gdbusobjectmanager.h"
24 #include "gdbusobjectmanagerserver.h"
25 #include "gdbusobject.h"
26 #include "gdbusobjectskeleton.h"
27 #include "gdbusinterfaceskeleton.h"
28 #include "gdbusconnection.h"
29 #include "gdbusintrospection.h"
30 #include "gdbusmethodinvocation.h"
31 #include "gdbuserror.h"
32
33 #include "gioerror.h"
34
35 #include "glibintl.h"
36
37 /**
38  * SECTION:gdbusobjectmanagerserver
39  * @short_description: Service-side object manager
40  * @include: gio/gio.h
41  *
42  * #GDBusObjectManagerServer is used to export #GDBusObject instances using
43  * the standardized
44  * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
45  * interface. For example, remote D-Bus clients can get all objects
46  * and properties in a single call. Additionally, any change in the
47  * object hierarchy is broadcast using signals. This means that D-Bus
48  * clients can keep caches up to date by only listening to D-Bus
49  * signals.
50  *
51  * The recommended path to export an object manager at is the path form of the
52  * well-known name of a D-Bus service, or below. For example, if a D-Bus service
53  * is available at the well-known name `net.example.ExampleService1`, the object
54  * manager should typically be exported at `/net/example/ExampleService1`, or
55  * below (to allow for multiple object managers in a service).
56  *
57  * It is supported, but not recommended, to export an object manager at the root
58  * path, `/`.
59  *
60  * See #GDBusObjectManagerClient for the client-side code that is
61  * intended to be used with #GDBusObjectManagerServer or any D-Bus
62  * object implementing the org.freedesktop.DBus.ObjectManager
63  * interface.
64  */
65
66 typedef struct
67 {
68   GDBusObjectSkeleton *object;
69   GDBusObjectManagerServer *manager;
70   GHashTable *map_iface_name_to_iface;
71   gboolean exported;
72 } RegistrationData;
73
74 static void registration_data_free (RegistrationData *data);
75
76 static void export_all (GDBusObjectManagerServer *manager);
77 static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager);
78
79 static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
80                                                          RegistrationData   *data,
81                                                          const gchar *const *interfaces,
82                                                          const gchar *object_path);
83
84 static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
85                                                            RegistrationData   *data,
86                                                            const gchar *const *interfaces);
87
88 static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer  *manager,
89                                                                 const gchar               *object_path);
90
91 struct _GDBusObjectManagerServerPrivate
92 {
93   GMutex lock;
94   GDBusConnection *connection;
95   gchar *object_path;
96   gchar *object_path_ending_in_slash;
97   GHashTable *map_object_path_to_data;
98   guint manager_reg_id;
99 };
100
101 enum
102 {
103   PROP_0,
104   PROP_CONNECTION,
105   PROP_OBJECT_PATH
106 };
107
108 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
109
110 G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT,
111                          G_ADD_PRIVATE (GDBusObjectManagerServer)
112                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
113
114 static void g_dbus_object_manager_server_constructed (GObject *object);
115
116 static void
117 g_dbus_object_manager_server_finalize (GObject *object)
118 {
119   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
120
121   if (manager->priv->connection != NULL)
122     {
123       unexport_all (manager, TRUE);
124       g_object_unref (manager->priv->connection);
125     }
126   g_hash_table_unref (manager->priv->map_object_path_to_data);
127   g_free (manager->priv->object_path);
128   g_free (manager->priv->object_path_ending_in_slash);
129
130   g_mutex_clear (&manager->priv->lock);
131
132   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL)
133     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object);
134 }
135
136 static void
137 g_dbus_object_manager_server_get_property (GObject    *object,
138                                            guint       prop_id,
139                                            GValue     *value,
140                                            GParamSpec *pspec)
141 {
142   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
143
144   switch (prop_id)
145     {
146     case PROP_CONNECTION:
147       g_mutex_lock (&manager->priv->lock);
148       g_value_set_object (value, manager->priv->connection);
149       g_mutex_unlock (&manager->priv->lock);
150       break;
151
152     case PROP_OBJECT_PATH:
153       g_value_set_string (value, g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
154       break;
155
156     default:
157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158       break;
159     }
160 }
161
162 static void
163 g_dbus_object_manager_server_set_property (GObject       *object,
164                                            guint          prop_id,
165                                            const GValue  *value,
166                                            GParamSpec    *pspec)
167 {
168   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
169
170   switch (prop_id)
171     {
172     case PROP_CONNECTION:
173       g_dbus_object_manager_server_set_connection (manager, g_value_get_object (value));
174       break;
175
176     case PROP_OBJECT_PATH:
177       g_assert (manager->priv->object_path == NULL);
178       g_assert (g_variant_is_object_path (g_value_get_string (value)));
179       manager->priv->object_path = g_value_dup_string (value);
180       if (g_str_equal (manager->priv->object_path, "/"))
181         manager->priv->object_path_ending_in_slash = g_strdup (manager->priv->object_path);
182       else
183         manager->priv->object_path_ending_in_slash = g_strdup_printf ("%s/", manager->priv->object_path);
184       break;
185
186     default:
187       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188       break;
189     }
190 }
191
192 static void
193 g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
194 {
195   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
196
197   gobject_class->finalize     = g_dbus_object_manager_server_finalize;
198   gobject_class->constructed  = g_dbus_object_manager_server_constructed;
199   gobject_class->set_property = g_dbus_object_manager_server_set_property;
200   gobject_class->get_property = g_dbus_object_manager_server_get_property;
201
202   /**
203    * GDBusObjectManagerServer:connection:
204    *
205    * The #GDBusConnection to export objects on.
206    *
207    * Since: 2.30
208    */
209   g_object_class_install_property (gobject_class,
210                                    PROP_CONNECTION,
211                                    g_param_spec_object ("connection",
212                                                         "Connection",
213                                                         "The connection to export objects on",
214                                                         G_TYPE_DBUS_CONNECTION,
215                                                         G_PARAM_READABLE |
216                                                         G_PARAM_WRITABLE |
217                                                         G_PARAM_STATIC_STRINGS));
218
219   /**
220    * GDBusObjectManagerServer:object-path:
221    *
222    * The object path to register the manager object at.
223    *
224    * Since: 2.30
225    */
226   g_object_class_install_property (gobject_class,
227                                    PROP_OBJECT_PATH,
228                                    g_param_spec_string ("object-path",
229                                                         "Object Path",
230                                                         "The object path to register the manager object at",
231                                                         NULL,
232                                                         G_PARAM_READABLE |
233                                                         G_PARAM_WRITABLE |
234                                                         G_PARAM_CONSTRUCT_ONLY |
235                                                         G_PARAM_STATIC_STRINGS));
236 }
237
238 static void
239 g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
240 {
241   manager->priv = g_dbus_object_manager_server_get_instance_private (manager);
242   g_mutex_init (&manager->priv->lock);
243   manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
244                                                                   g_str_equal,
245                                                                   g_free,
246                                                                   (GDestroyNotify) registration_data_free);
247 }
248
249 /**
250  * g_dbus_object_manager_server_new:
251  * @object_path: The object path to export the manager object at.
252  *
253  * Creates a new #GDBusObjectManagerServer object.
254  *
255  * The returned server isn't yet exported on any connection. To do so,
256  * use g_dbus_object_manager_server_set_connection(). Normally you
257  * want to export all of your objects before doing so to avoid
258  * [InterfacesAdded](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
259  * signals being emitted.
260  *
261  * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
262  *
263  * Since: 2.30
264  */
265 GDBusObjectManagerServer *
266 g_dbus_object_manager_server_new (const gchar     *object_path)
267 {
268   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
269   return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
270                                                      "object-path", object_path,
271                                                      NULL));
272 }
273
274 /**
275  * g_dbus_object_manager_server_set_connection:
276  * @manager: A #GDBusObjectManagerServer.
277  * @connection: (nullable): A #GDBusConnection or %NULL.
278  *
279  * Exports all objects managed by @manager on @connection. If
280  * @connection is %NULL, stops exporting objects.
281  */
282 void
283 g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer  *manager,
284                                              GDBusConnection           *connection)
285 {
286   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
287   g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection));
288
289   g_mutex_lock (&manager->priv->lock);
290
291   if (manager->priv->connection == connection)
292     {
293       g_mutex_unlock (&manager->priv->lock);
294       goto out;
295     }
296
297   if (manager->priv->connection != NULL)
298     {
299       unexport_all (manager, FALSE);
300       g_object_unref (manager->priv->connection);
301       manager->priv->connection = NULL;
302     }
303
304   manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL;
305   if (manager->priv->connection != NULL)
306     export_all (manager);
307
308   g_mutex_unlock (&manager->priv->lock);
309
310   g_object_notify (G_OBJECT (manager), "connection");
311  out:
312   ;
313 }
314
315 /**
316  * g_dbus_object_manager_server_get_connection:
317  * @manager: A #GDBusObjectManagerServer
318  *
319  * Gets the #GDBusConnection used by @manager.
320  *
321  * Returns: (transfer full): A #GDBusConnection object or %NULL if
322  *   @manager isn't exported on a connection. The returned object should
323  *   be freed with g_object_unref().
324  *
325  * Since: 2.30
326  */
327 GDBusConnection *
328 g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
329 {
330   GDBusConnection *ret;
331   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
332   g_mutex_lock (&manager->priv->lock);
333   ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL;
334   g_mutex_unlock (&manager->priv->lock);
335   return ret;
336 }
337
338 /* ---------------------------------------------------------------------------------------------------- */
339
340 static void
341 registration_data_export_interface (RegistrationData        *data,
342                                     GDBusInterfaceSkeleton  *interface_skeleton,
343                                     const gchar             *object_path)
344 {
345   GDBusInterfaceInfo *info;
346   GError *error;
347
348   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
349   error = NULL;
350   if (data->manager->priv->connection != NULL)
351     {
352       if (!g_dbus_interface_skeleton_export (interface_skeleton,
353                                              data->manager->priv->connection,
354                                              object_path,
355                                              &error))
356         {
357           g_warning ("%s: Error registering object at %s with interface %s: %s",
358                      G_STRLOC,
359                      object_path,
360                      info->name,
361                      error->message);
362           g_error_free (error);
363         }
364     }
365
366   g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
367   g_hash_table_insert (data->map_iface_name_to_iface,
368                        info->name,
369                        g_object_ref (interface_skeleton));
370
371   /* if we are already exported, then... */
372   if (data->exported)
373     {
374       const gchar *interfaces[2];
375       /* emit InterfacesAdded on the ObjectManager object */
376       interfaces[0] = info->name;
377       interfaces[1] = NULL;
378       g_dbus_object_manager_server_emit_interfaces_added (data->manager, data, interfaces, object_path);
379     }
380 }
381
382 static void
383 registration_data_unexport_interface (RegistrationData       *data,
384                                       GDBusInterfaceSkeleton *interface_skeleton)
385 {
386   GDBusInterfaceInfo *info;
387   GDBusInterfaceSkeleton *iface;
388
389   info = g_dbus_interface_skeleton_get_info (interface_skeleton);
390   iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
391   g_assert (iface != NULL);
392
393   if (data->manager->priv->connection != NULL)
394     g_dbus_interface_skeleton_unexport (iface);
395
396   g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
397
398   /* if we are already exported, then... */
399   if (data->exported)
400     {
401       const gchar *interfaces[2];
402       /* emit InterfacesRemoved on the ObjectManager object */
403       interfaces[0] = info->name;
404       interfaces[1] = NULL;
405       g_dbus_object_manager_server_emit_interfaces_removed (data->manager, data, interfaces);
406     }
407 }
408
409 /* ---------------------------------------------------------------------------------------------------- */
410
411 static void
412 on_interface_added (GDBusObject    *object,
413                     GDBusInterface *interface,
414                     gpointer        user_data)
415 {
416   RegistrationData *data = user_data;
417   const gchar *object_path;
418   g_mutex_lock (&data->manager->priv->lock);
419   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
420   registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface), object_path);
421   g_mutex_unlock (&data->manager->priv->lock);
422 }
423
424 static void
425 on_interface_removed (GDBusObject    *object,
426                       GDBusInterface *interface,
427                       gpointer        user_data)
428 {
429   RegistrationData *data = user_data;
430   g_mutex_lock (&data->manager->priv->lock);
431   registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
432   g_mutex_unlock (&data->manager->priv->lock);
433 }
434
435 /* ---------------------------------------------------------------------------------------------------- */
436
437
438 static void
439 registration_data_free (RegistrationData *data)
440 {
441   GHashTableIter iter;
442   GDBusInterfaceSkeleton *iface;
443
444   data->exported = FALSE;
445
446   g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
447   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
448     {
449       if (data->manager->priv->connection != NULL)
450         g_dbus_interface_skeleton_unexport (iface);
451     }
452
453   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
454   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data);
455   g_object_unref (data->object);
456   g_hash_table_destroy (data->map_iface_name_to_iface);
457   g_free (data);
458 }
459
460 /* ---------------------------------------------------------------------------------------------------- */
461
462 static void
463 g_dbus_object_manager_server_export_unlocked (GDBusObjectManagerServer  *manager,
464                                               GDBusObjectSkeleton       *object,
465                                               const gchar               *object_path)
466 {
467   RegistrationData *data;
468   GList *existing_interfaces;
469   GList *l;
470   GPtrArray *interface_names;
471
472   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
473   g_return_if_fail (G_IS_DBUS_OBJECT (object));
474   g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash));
475
476   interface_names = g_ptr_array_new ();
477
478   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
479   if (data != NULL)
480     g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
481
482   data = g_new0 (RegistrationData, 1);
483   data->object = g_object_ref (object);
484   data->manager = manager;
485   data->map_iface_name_to_iface = g_hash_table_new_full (g_str_hash,
486                                                          g_str_equal,
487                                                          NULL,
488                                                          (GDestroyNotify) g_object_unref);
489
490   g_signal_connect (object,
491                     "interface-added",
492                     G_CALLBACK (on_interface_added),
493                     data);
494   g_signal_connect (object,
495                     "interface-removed",
496                     G_CALLBACK (on_interface_removed),
497                     data);
498
499   /* Register all known interfaces - note that data->exported is FALSE so
500    * we don't emit any InterfacesAdded signals.
501    */
502   existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
503   for (l = existing_interfaces; l != NULL; l = l->next)
504     {
505       GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (l->data);
506       registration_data_export_interface (data, interface_skeleton, object_path);
507       g_ptr_array_add (interface_names, g_dbus_interface_skeleton_get_info (interface_skeleton)->name);
508     }
509   g_list_free_full (existing_interfaces, g_object_unref);
510   g_ptr_array_add (interface_names, NULL);
511
512   data->exported = TRUE;
513
514   /* now emit InterfacesAdded() for all the interfaces */
515   g_dbus_object_manager_server_emit_interfaces_added (manager, data, (const gchar *const *) interface_names->pdata, object_path);
516   g_ptr_array_unref (interface_names);
517
518   g_hash_table_insert (manager->priv->map_object_path_to_data,
519                        g_strdup (object_path),
520                        data);
521 }
522
523 /**
524  * g_dbus_object_manager_server_export:
525  * @manager: A #GDBusObjectManagerServer.
526  * @object: A #GDBusObjectSkeleton.
527  *
528  * Exports @object on @manager.
529  *
530  * If there is already a #GDBusObject exported at the object path,
531  * then the old object is removed.
532  *
533  * The object path for @object must be in the hierarchy rooted by the
534  * object path for @manager.
535  *
536  * Note that @manager will take a reference on @object for as long as
537  * it is exported.
538  *
539  * Since: 2.30
540  */
541 void
542 g_dbus_object_manager_server_export (GDBusObjectManagerServer  *manager,
543                                      GDBusObjectSkeleton       *object)
544 {
545   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
546   g_mutex_lock (&manager->priv->lock);
547   g_dbus_object_manager_server_export_unlocked (manager, object,
548                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
549   g_mutex_unlock (&manager->priv->lock);
550 }
551
552 /**
553  * g_dbus_object_manager_server_export_uniquely:
554  * @manager: A #GDBusObjectManagerServer.
555  * @object: An object.
556  *
557  * Like g_dbus_object_manager_server_export() but appends a string of
558  * the form _N (with N being a natural number) to @object's object path
559  * if an object with the given path already exists. As such, the
560  * #GDBusObjectProxy:g-object-path property of @object may be modified.
561  *
562  * Since: 2.30
563  */
564 void
565 g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
566                                               GDBusObjectSkeleton      *object)
567 {
568   gchar *orig_object_path;
569   gchar *object_path;
570   guint count;
571   gboolean modified;
572
573   orig_object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
574
575   g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
576   g_return_if_fail (G_IS_DBUS_OBJECT (object));
577   g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash));
578
579   g_mutex_lock (&manager->priv->lock);
580
581   object_path = g_strdup (orig_object_path);
582   count = 1;
583   modified = FALSE;
584   while (TRUE)
585     {
586       RegistrationData *data;
587       data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
588       if (data == NULL)
589         {
590           break;
591         }
592       g_free (object_path);
593       object_path = g_strdup_printf ("%s_%d", orig_object_path, count++);
594       modified = TRUE;
595     }
596
597   g_dbus_object_manager_server_export_unlocked (manager, object, object_path);
598
599   g_mutex_unlock (&manager->priv->lock);
600
601   if (modified)
602     g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
603
604   g_free (object_path);
605   g_free (orig_object_path);
606
607 }
608
609 /**
610  * g_dbus_object_manager_server_is_exported:
611  * @manager: A #GDBusObjectManagerServer.
612  * @object: An object.
613  *
614  * Returns whether @object is currently exported on @manager.
615  *
616  * Returns: %TRUE if @object is exported
617  *
618  * Since: 2.34
619  **/
620 gboolean
621 g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager,
622                                           GDBusObjectSkeleton      *object)
623 {
624   RegistrationData *data = NULL;
625   const gchar *object_path;
626   gboolean object_is_exported;
627
628   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
629   g_return_val_if_fail (G_IS_DBUS_OBJECT (object), FALSE);
630
631   g_mutex_lock (&manager->priv->lock);
632
633   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
634   if (object_path != NULL)
635     data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
636   object_is_exported = (data != NULL);
637
638   g_mutex_unlock (&manager->priv->lock);
639
640   return object_is_exported;
641 }
642
643 /* ---------------------------------------------------------------------------------------------------- */
644
645 static gboolean
646 g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer  *manager,
647                                                 const gchar               *object_path)
648 {
649   RegistrationData *data;
650   gboolean ret;
651
652   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
653   g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
654   g_return_val_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash), FALSE);
655
656   ret = FALSE;
657
658   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
659   if (data != NULL)
660     {
661       GPtrArray *interface_names;
662       GHashTableIter iter;
663       const gchar *iface_name;
664
665       interface_names = g_ptr_array_new ();
666       g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
667       while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
668         g_ptr_array_add (interface_names, (gpointer) iface_name);
669       g_ptr_array_add (interface_names, NULL);
670       /* now emit InterfacesRemoved() for all the interfaces */
671       g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
672       g_ptr_array_unref (interface_names);
673
674       g_hash_table_remove (manager->priv->map_object_path_to_data, object_path);
675       ret = TRUE;
676     }
677
678   return ret;
679 }
680
681 /**
682  * g_dbus_object_manager_server_unexport:
683  * @manager: A #GDBusObjectManagerServer.
684  * @object_path: An object path.
685  *
686  * If @manager has an object at @path, removes the object. Otherwise
687  * does nothing.
688  *
689  * Note that @object_path must be in the hierarchy rooted by the
690  * object path for @manager.
691  *
692  * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise.
693  *
694  * Since: 2.30
695  */
696 gboolean
697 g_dbus_object_manager_server_unexport (GDBusObjectManagerServer  *manager,
698                                        const gchar         *object_path)
699 {
700   gboolean ret;
701   g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
702   g_mutex_lock (&manager->priv->lock);
703   ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
704   g_mutex_unlock (&manager->priv->lock);
705   return ret;
706 }
707
708
709 /* ---------------------------------------------------------------------------------------------------- */
710
711 static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
712 {
713   -1,
714   "object_path",
715   "o",
716   (GDBusAnnotationInfo**) NULL,
717 };
718
719 static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
720 {
721   -1,
722   "interfaces_and_properties",
723   "a{sa{sv}}",
724   (GDBusAnnotationInfo**) NULL,
725 };
726
727 static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
728 {
729   &manager_interfaces_added_signal_info_arg0,
730   &manager_interfaces_added_signal_info_arg1,
731   NULL
732 };
733
734 static const GDBusSignalInfo manager_interfaces_added_signal_info =
735 {
736   -1,
737   "InterfacesAdded",
738   (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
739   (GDBusAnnotationInfo**) NULL
740 };
741
742 /* ---------- */
743
744 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
745 {
746   -1,
747   "object_path",
748   "o",
749   (GDBusAnnotationInfo**) NULL,
750 };
751
752 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
753 {
754   -1,
755   "interfaces",
756   "as",
757   (GDBusAnnotationInfo**) NULL,
758 };
759
760 static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
761 {
762   &manager_interfaces_removed_signal_info_arg0,
763   &manager_interfaces_removed_signal_info_arg1,
764   NULL
765 };
766
767 static const GDBusSignalInfo manager_interfaces_removed_signal_info =
768 {
769   -1,
770   "InterfacesRemoved",
771   (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
772   (GDBusAnnotationInfo**) NULL
773 };
774
775 /* ---------- */
776
777 static const GDBusSignalInfo * const manager_signal_info_pointers[] =
778 {
779   &manager_interfaces_added_signal_info,
780   &manager_interfaces_removed_signal_info,
781   NULL
782 };
783
784 /* ---------- */
785
786 static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
787 {
788   -1,
789   "object_paths_interfaces_and_properties",
790   "a{oa{sa{sv}}}",
791   (GDBusAnnotationInfo**) NULL,
792 };
793
794 static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
795 {
796   &manager_get_all_method_info_out_arg0,
797   NULL
798 };
799
800 static const GDBusMethodInfo manager_get_all_method_info =
801 {
802   -1,
803   "GetManagedObjects",
804   (GDBusArgInfo**) NULL,
805   (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
806   (GDBusAnnotationInfo**) NULL
807 };
808
809 static const GDBusMethodInfo * const manager_method_info_pointers[] =
810 {
811   &manager_get_all_method_info,
812   NULL
813 };
814
815 /* ---------- */
816
817 static const GDBusInterfaceInfo manager_interface_info =
818 {
819   -1,
820   "org.freedesktop.DBus.ObjectManager",
821   (GDBusMethodInfo **) manager_method_info_pointers,
822   (GDBusSignalInfo **) manager_signal_info_pointers,
823   (GDBusPropertyInfo **) NULL,
824   (GDBusAnnotationInfo **) NULL
825 };
826
827 static void
828 manager_method_call (GDBusConnection       *connection,
829                      const gchar           *sender,
830                      const gchar           *object_path,
831                      const gchar           *interface_name,
832                      const gchar           *method_name,
833                      GVariant              *parameters,
834                      GDBusMethodInvocation *invocation,
835                      gpointer               user_data)
836 {
837   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
838   GVariantBuilder array_builder;
839   GHashTableIter object_iter;
840   RegistrationData *data;
841
842   g_mutex_lock (&manager->priv->lock);
843
844   if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
845     {
846       g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
847       g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
848       while (g_hash_table_iter_next (&object_iter, NULL, (gpointer) &data))
849         {
850           GVariantBuilder interfaces_builder;
851           GHashTableIter interface_iter;
852           GDBusInterfaceSkeleton *iface;
853           const gchar *iter_object_path;
854
855           g_variant_builder_init (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
856           g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
857           while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
858             {
859               GVariant *properties = g_dbus_interface_skeleton_get_properties (iface);
860               g_variant_builder_add (&interfaces_builder, "{s@a{sv}}",
861                                      g_dbus_interface_skeleton_get_info (iface)->name,
862                                      properties);
863               g_variant_unref (properties);
864             }
865           iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
866           g_variant_builder_add (&array_builder,
867                                  "{oa{sa{sv}}}",
868                                  iter_object_path,
869                                  &interfaces_builder);
870         }
871
872       g_dbus_method_invocation_return_value (invocation,
873                                              g_variant_new ("(a{oa{sa{sv}}})",
874                                                             &array_builder));
875     }
876   else
877     {
878       g_dbus_method_invocation_return_error (invocation,
879                                              G_DBUS_ERROR,
880                                              G_DBUS_ERROR_UNKNOWN_METHOD,
881                                              "Unknown method %s - only GetManagedObjects() is supported",
882                                              method_name);
883     }
884   g_mutex_unlock (&manager->priv->lock);
885 }
886
887 static const GDBusInterfaceVTable manager_interface_vtable =
888 {
889   manager_method_call, /* handle_method_call */
890   NULL, /* get_property */
891   NULL  /* set_property */
892 };
893
894 /* ---------------------------------------------------------------------------------------------------- */
895
896 static void
897 g_dbus_object_manager_server_constructed (GObject *object)
898 {
899   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
900
901   if (manager->priv->connection != NULL)
902     export_all (manager);
903
904   if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
905     G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
906 }
907
908 static void
909 g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
910                                                     RegistrationData   *data,
911                                                     const gchar *const *interfaces,
912                                                     const gchar *object_path)
913 {
914   GVariantBuilder array_builder;
915   GError *error;
916   guint n;
917
918   if (data->manager->priv->connection == NULL)
919     goto out;
920
921   g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
922   for (n = 0; interfaces[n] != NULL; n++)
923     {
924       GDBusInterfaceSkeleton *iface;
925       GVariant *properties;
926
927       iface = g_hash_table_lookup (data->map_iface_name_to_iface, interfaces[n]);
928       g_assert (iface != NULL);
929       properties = g_dbus_interface_skeleton_get_properties (iface);
930       g_variant_builder_add (&array_builder, "{s@a{sv}}", interfaces[n], properties);
931       g_variant_unref (properties);
932     }
933
934   error = NULL;
935   g_dbus_connection_emit_signal (data->manager->priv->connection,
936                                  NULL, /* destination_bus_name */
937                                  manager->priv->object_path,
938                                  manager_interface_info.name,
939                                  "InterfacesAdded",
940                                  g_variant_new ("(oa{sa{sv}})",
941                                                 object_path,
942                                                 &array_builder),
943                                  &error);
944   if (error)
945     {
946       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
947         g_warning ("Couldn't emit InterfacesAdded signal: %s", error->message);
948       g_error_free (error);
949     }
950  out:
951   ;
952 }
953
954 static void
955 g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
956                                                       RegistrationData   *data,
957                                                       const gchar *const *interfaces)
958 {
959   GVariantBuilder array_builder;
960   GError *error;
961   guint n;
962   const gchar *object_path;
963
964   if (data->manager->priv->connection == NULL)
965     goto out;
966
967   g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
968   for (n = 0; interfaces[n] != NULL; n++)
969     g_variant_builder_add (&array_builder, "s", interfaces[n]);
970
971   error = NULL;
972   object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
973   g_dbus_connection_emit_signal (data->manager->priv->connection,
974                                  NULL, /* destination_bus_name */
975                                  manager->priv->object_path,
976                                  manager_interface_info.name,
977                                  "InterfacesRemoved",
978                                  g_variant_new ("(oas)",
979                                                 object_path,
980                                                 &array_builder),
981                                  &error);
982   if (error)
983     {
984       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
985         g_warning ("Couldn't emit InterfacesRemoved signal: %s", error->message);
986       g_error_free (error);
987     }
988  out:
989   ;
990 }
991
992 /* ---------------------------------------------------------------------------------------------------- */
993
994 static GList *
995 g_dbus_object_manager_server_get_objects (GDBusObjectManager  *_manager)
996 {
997   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
998   GList *ret;
999   GHashTableIter iter;
1000   RegistrationData *data;
1001
1002   g_mutex_lock (&manager->priv->lock);
1003
1004   ret = NULL;
1005   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1006   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1007     {
1008       ret = g_list_prepend (ret, g_object_ref (data->object));
1009     }
1010
1011   g_mutex_unlock (&manager->priv->lock);
1012
1013   return ret;
1014 }
1015
1016 static const gchar *
1017 g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
1018 {
1019   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1020   return manager->priv->object_path;
1021 }
1022
1023 static GDBusObject *
1024 g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
1025                                          const gchar        *object_path)
1026 {
1027   GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1028   GDBusObject *ret;
1029   RegistrationData *data;
1030
1031   ret = NULL;
1032
1033   g_mutex_lock (&manager->priv->lock);
1034   data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
1035   if (data != NULL)
1036     ret = g_object_ref (G_DBUS_OBJECT (data->object));
1037   g_mutex_unlock (&manager->priv->lock);
1038
1039   return ret;
1040 }
1041
1042 static GDBusInterface *
1043 g_dbus_object_manager_server_get_interface  (GDBusObjectManager  *_manager,
1044                                              const gchar         *object_path,
1045                                              const gchar         *interface_name)
1046 {
1047   GDBusInterface *ret;
1048   GDBusObject *object;
1049
1050   ret = NULL;
1051
1052   object = g_dbus_object_manager_get_object (_manager, object_path);
1053   if (object == NULL)
1054     goto out;
1055
1056   ret = g_dbus_object_get_interface (object, interface_name);
1057   g_object_unref (object);
1058
1059  out:
1060   return ret;
1061 }
1062
1063 static void
1064 dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1065 {
1066   iface->get_object_path = g_dbus_object_manager_server_get_object_path;
1067   iface->get_objects     = g_dbus_object_manager_server_get_objects;
1068   iface->get_object      = g_dbus_object_manager_server_get_object;
1069   iface->get_interface   = g_dbus_object_manager_server_get_interface;
1070 }
1071
1072 /* ---------------------------------------------------------------------------------------------------- */
1073
1074 static void
1075 export_all (GDBusObjectManagerServer *manager)
1076 {
1077   GHashTableIter iter;
1078   const gchar *object_path;
1079   RegistrationData *data;
1080   GHashTableIter iface_iter;
1081   GDBusInterfaceSkeleton *iface;
1082   GError *error;
1083
1084   g_return_if_fail (manager->priv->connection != NULL);
1085
1086   error = NULL;
1087   g_warn_if_fail (manager->priv->manager_reg_id == 0);
1088   manager->priv->manager_reg_id = g_dbus_connection_register_object (manager->priv->connection,
1089                                                                      manager->priv->object_path,
1090                                                                      (GDBusInterfaceInfo *) &manager_interface_info,
1091                                                                      &manager_interface_vtable,
1092                                                                      manager,
1093                                                                      NULL, /* user_data_free_func */
1094                                                                      &error);
1095   if (manager->priv->manager_reg_id == 0)
1096     {
1097       g_warning ("%s: Error registering manager at %s: %s",
1098                  G_STRLOC,
1099                  manager->priv->object_path,
1100                  error->message);
1101       g_error_free (error);
1102     }
1103
1104   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1105   while (g_hash_table_iter_next (&iter, (gpointer) &object_path, (gpointer) &data))
1106     {
1107       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1108       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1109         {
1110           g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL);
1111           error = NULL;
1112           if (!g_dbus_interface_skeleton_export (iface,
1113                                                  manager->priv->connection,
1114                                                  object_path,
1115                                                  &error))
1116             {
1117               g_warning ("%s: Error registering object at %s with interface %s: %s",
1118                          G_STRLOC,
1119                          object_path,
1120                          g_dbus_interface_skeleton_get_info (iface)->name,
1121                          error->message);
1122               g_error_free (error);
1123             }
1124         }
1125     }
1126 }
1127
1128 static void
1129 unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager)
1130 {
1131   GHashTableIter iter;
1132   RegistrationData *data;
1133   GHashTableIter iface_iter;
1134   GDBusInterfaceSkeleton *iface;
1135
1136   g_return_if_fail (manager->priv->connection != NULL);
1137
1138   g_warn_if_fail (manager->priv->manager_reg_id > 0);
1139   if (manager->priv->manager_reg_id > 0)
1140     {
1141       g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection,
1142                                                            manager->priv->manager_reg_id));
1143       manager->priv->manager_reg_id = 0;
1144     }
1145   if (only_manager)
1146     goto out;
1147
1148   g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1149   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1150     {
1151       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1152       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1153         {
1154           g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
1155           g_dbus_interface_skeleton_unexport (iface);
1156         }
1157     }
1158  out:
1159   ;
1160 }
1161
1162 /* ---------------------------------------------------------------------------------------------------- */