1 /*
2  * dbus-daemon.c - Source for TpDBusDaemon
3  *
4  * Copyright (C) 2005-2009 Collabora Ltd. <http://www.collabora.co.uk/>
5  * Copyright (C) 2005-2009 Nokia Corporation
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "config.h"
23 
24 #include <telepathy-glib/dbus.h>
25 #include <telepathy-glib/dbus-internal.h>
26 
27 #include <dbus/dbus.h>
28 #include <dbus/dbus-glib-lowlevel.h>
29 
30 #include <telepathy-glib/errors.h>
31 #include <telepathy-glib/interfaces.h>
32 #include <telepathy-glib/proxy-subclass.h>
33 #include <telepathy-glib/util.h>
34 
35 #include "telepathy-glib/_gen/tp-cli-dbus-daemon-body.h"
36 
37 #define DEBUG_FLAG TP_DEBUG_PROXY
38 #include "debug-internal.h"
39 
40 /**
41  * TpDBusDaemonClass:
42  *
43  * The class of #TpDBusDaemon.
44  *
45  * Since: 0.7.1
46  */
47 struct _TpDBusDaemonClass
48 {
49   /*<private>*/
50   TpProxyClass parent_class;
51   gpointer priv;
52 };
53 
54 /**
55  * TpDBusDaemon:
56  *
57  * A subclass of #TpProxy that represents the D-Bus daemon. It mainly provides
58  * functionality to manage well-known names on the bus.
59  *
60  * Since: 0.7.1
61  */
62 struct _TpDBusDaemon
63 {
64   /*<private>*/
65   TpProxy parent;
66 
67   TpDBusDaemonPrivate *priv;
68 };
69 
70 struct _TpDBusDaemonPrivate
71 {
72   /* dup'd name => _NameOwnerWatch */
73   GHashTable *name_owner_watches;
74   /* reffed */
75   DBusConnection *libdbus;
76 };
77 
78 G_DEFINE_TYPE (TpDBusDaemon, tp_dbus_daemon, TP_TYPE_PROXY)
79 
80 static gpointer starter_bus_daemon = NULL;
81 
82 /**
83  * tp_dbus_daemon_dup:
84  * @error: Used to indicate error if %NULL is returned
85  *
86  * Returns a proxy for signals and method calls on the D-Bus daemon on which
87  * this process was activated (if it was launched by D-Bus service
88  * activation), or the session bus (otherwise).
89  *
90  * If it is not possible to connect to the appropriate bus, raise an error
91  * and return %NULL.
92  *
93  * The returned #TpDBusDaemon is cached; the same #TpDBusDaemon object will
94  * be returned by this function repeatedly, as long as at least one reference
95  * exists.
96  *
97  * Returns: (transfer full): a reference to a proxy for signals and method
98  *  calls on the bus daemon, or %NULL
99  *
100  * Since: 0.7.26
101  */
102 TpDBusDaemon *
tp_dbus_daemon_dup(GError ** error)103 tp_dbus_daemon_dup (GError **error)
104 {
105   DBusGConnection *conn;
106 
107   if (starter_bus_daemon != NULL)
108     return g_object_ref (starter_bus_daemon);
109 
110   conn = _tp_dbus_starter_bus_conn (error);
111 
112   if (conn == NULL)
113     return NULL;
114 
115   starter_bus_daemon = tp_dbus_daemon_new (conn);
116   g_assert (starter_bus_daemon != NULL);
117   g_object_add_weak_pointer (starter_bus_daemon, &starter_bus_daemon);
118 
119   return starter_bus_daemon;
120 }
121 
122 /**
123  * tp_dbus_daemon_new: (skip)
124  * @connection: a connection to D-Bus
125  *
126  * Returns a proxy for signals and method calls on a particular bus
127  * connection.
128  *
129  * Use tp_dbus_daemon_dup() instead if you just want a connection to the
130  * starter or session bus (which is almost always the right thing for
131  * Telepathy).
132  *
133  * Returns: a new proxy for signals and method calls on the bus daemon
134  *  to which @connection is connected
135  *
136  * Since: 0.7.1
137  */
138 TpDBusDaemon *
tp_dbus_daemon_new(DBusGConnection * connection)139 tp_dbus_daemon_new (DBusGConnection *connection)
140 {
141   g_return_val_if_fail (connection != NULL, NULL);
142 
143   return TP_DBUS_DAEMON (g_object_new (TP_TYPE_DBUS_DAEMON,
144         "dbus-connection", connection,
145         "bus-name", DBUS_SERVICE_DBUS,
146         "object-path", DBUS_PATH_DBUS,
147         NULL));
148 }
149 
150 typedef struct
151 {
152   gchar *last_owner;
153   GArray *callbacks;
154   gsize invoking;
155 } _NameOwnerWatch;
156 
157 typedef struct
158 {
159   TpDBusDaemonNameOwnerChangedCb callback;
160   gpointer user_data;
161   GDestroyNotify destroy;
162 } _NameOwnerSubWatch;
163 
164 static void _tp_dbus_daemon_stop_watching (TpDBusDaemon *self,
165     const gchar *name, _NameOwnerWatch *watch);
166 
167 static void
tp_dbus_daemon_maybe_free_name_owner_watch(TpDBusDaemon * self,const gchar * name,_NameOwnerWatch * watch)168 tp_dbus_daemon_maybe_free_name_owner_watch (TpDBusDaemon *self,
169     const gchar *name,
170     _NameOwnerWatch *watch)
171 {
172   /* Check to see whether this (callback, user_data) pair is in the watch's
173    * array of callbacks. */
174   GArray *array = watch->callbacks;
175   /* 1 greater than an index into @array, to avoid it going negative: we
176    * iterate in reverse so we can delete elements without needing to adjust
177    * @i to compensate */
178   guint i;
179 
180   if (watch->invoking > 0)
181     return;
182 
183   for (i = array->len; i > 0; i--)
184     {
185       _NameOwnerSubWatch *entry = &g_array_index (array,
186           _NameOwnerSubWatch, i - 1);
187 
188       if (entry->callback != NULL)
189         continue;
190 
191       if (entry->destroy != NULL)
192         entry->destroy (entry->user_data);
193 
194       g_array_remove_index (array, i - 1);
195     }
196 
197   if (array->len == 0)
198     {
199       _tp_dbus_daemon_stop_watching (self, name, watch);
200       g_hash_table_remove (self->priv->name_owner_watches, name);
201     }
202 }
203 
204 static void
_tp_dbus_daemon_name_owner_changed(TpDBusDaemon * self,const gchar * name,const gchar * new_owner)205 _tp_dbus_daemon_name_owner_changed (TpDBusDaemon *self,
206                                     const gchar *name,
207                                     const gchar *new_owner)
208 {
209   _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
210       name);
211   GArray *array;
212   guint i;
213 
214   if (watch == NULL)
215     return;
216 
217   /* This is partly to handle the case where an owner change happens
218    * while GetNameOwner is in flight, partly to be able to optimize by only
219    * calling GetNameOwner if we didn't already know, and partly because of a
220    * dbus-glib bug that means we get every signal twice
221    * (it thinks org.freedesktop.DBus is both a well-known name and a unique
222    * name). */
223   if (!tp_strdiff (watch->last_owner, new_owner))
224     return;
225 
226   g_free (watch->last_owner);
227   watch->last_owner = g_strdup (new_owner);
228 
229   /* We're calling out to user code which might end up removing its watch;
230    * tell it to be less destructive. Also hold a ref on self, to avoid it
231    * getting removed that way. */
232   array = watch->callbacks;
233   g_object_ref (self);
234   watch->invoking++;
235 
236   for (i = 0; i < array->len; i++)
237     {
238       _NameOwnerSubWatch *subwatch = &g_array_index (array,
239           _NameOwnerSubWatch, i);
240 
241       if (subwatch->callback != NULL)
242         subwatch->callback (self, name, new_owner, subwatch->user_data);
243     }
244 
245   watch->invoking--;
246 
247   tp_dbus_daemon_maybe_free_name_owner_watch (self, name, watch);
248   g_object_unref (self);
249 }
250 
251 static dbus_int32_t daemons_slot = -1;
252 
253 typedef struct {
254     DBusConnection *libdbus;
255     DBusMessage *message;
256 } NOCIdleContext;
257 
258 static NOCIdleContext *
noc_idle_context_new(DBusConnection * libdbus,DBusMessage * message)259 noc_idle_context_new (DBusConnection *libdbus,
260                       DBusMessage *message)
261 {
262   NOCIdleContext *context = g_slice_new (NOCIdleContext);
263 
264   context->libdbus = dbus_connection_ref (libdbus);
265   context->message = dbus_message_ref (message);
266   return context;
267 }
268 
269 static void
noc_idle_context_free(gpointer data)270 noc_idle_context_free (gpointer data)
271 {
272   NOCIdleContext *context = data;
273 
274   dbus_connection_unref (context->libdbus);
275   dbus_message_unref (context->message);
276   g_slice_free (NOCIdleContext, context);
277 }
278 
279 static gboolean
noc_idle_context_invoke(gpointer data)280 noc_idle_context_invoke (gpointer data)
281 {
282   NOCIdleContext *context = data;
283   const gchar *name;
284   const gchar *old_owner;
285   const gchar *new_owner;
286   DBusError dbus_error = DBUS_ERROR_INIT;
287   GSList **daemons;
288 
289   if (daemons_slot == -1)
290     return FALSE;
291 
292   if (!dbus_message_get_args (context->message, &dbus_error,
293         DBUS_TYPE_STRING, &name,
294         DBUS_TYPE_STRING, &old_owner,
295         DBUS_TYPE_STRING, &new_owner,
296         DBUS_TYPE_INVALID))
297     {
298       DEBUG ("Couldn't unpack NameOwnerChanged(s, s, s): %s: %s",
299           dbus_error.name, dbus_error.message);
300       dbus_error_free (&dbus_error);
301       return FALSE;
302     }
303 
304   daemons = dbus_connection_get_data (context->libdbus, daemons_slot);
305 
306   DEBUG ("NameOwnerChanged(%s, %s -> %s)", name, old_owner, new_owner);
307 
308   /* should always be non-NULL, barring bugs */
309   if (G_LIKELY (daemons != NULL))
310     {
311       GSList *iter;
312 
313       for (iter = *daemons; iter != NULL; iter = iter->next)
314         {
315           _tp_dbus_daemon_name_owner_changed (iter->data, name, new_owner);
316         }
317     }
318 
319   return FALSE;
320 }
321 
322 static DBusHandlerResult
_tp_dbus_daemon_name_owner_changed_filter(DBusConnection * libdbus,DBusMessage * message,void * unused G_GNUC_UNUSED)323 _tp_dbus_daemon_name_owner_changed_filter (DBusConnection *libdbus,
324                                            DBusMessage *message,
325                                            void *unused G_GNUC_UNUSED)
326 {
327   /* We have to do the real work in an idle, so we don't break re-entrant
328    * calls (the dbus-glib event source isn't re-entrant) */
329   if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS,
330         "NameOwnerChanged") &&
331       dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
332     g_idle_add_full (G_PRIORITY_HIGH, noc_idle_context_invoke,
333         noc_idle_context_new (libdbus, message),
334         noc_idle_context_free);
335 
336   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
337 }
338 
339 typedef struct {
340     TpDBusDaemon *self;
341     gchar *name;
342     DBusMessage *reply;
343     gsize refs;
344 } GetNameOwnerContext;
345 
346 static GetNameOwnerContext *
get_name_owner_context_new(TpDBusDaemon * self,const gchar * name)347 get_name_owner_context_new (TpDBusDaemon *self,
348                             const gchar *name)
349 {
350   GetNameOwnerContext *context = g_slice_new (GetNameOwnerContext);
351 
352   context->self = g_object_ref (self);
353   context->name = g_strdup (name);
354   context->reply = NULL;
355   context->refs = 1;
356   return context;
357 }
358 
359 static void
get_name_owner_context_unref(gpointer data)360 get_name_owner_context_unref (gpointer data)
361 {
362   GetNameOwnerContext *context = data;
363 
364   if (--context->refs == 0)
365     {
366       g_object_unref (context->self);
367       g_free (context->name);
368 
369       if (context->reply != NULL)
370         dbus_message_unref (context->reply);
371 
372       g_slice_free (GetNameOwnerContext, context);
373     }
374 }
375 
376 static gboolean
_tp_dbus_daemon_get_name_owner_idle(gpointer data)377 _tp_dbus_daemon_get_name_owner_idle (gpointer data)
378 {
379   GetNameOwnerContext *context = data;
380   const gchar *owner = "";
381 
382   if (context->reply == NULL)
383     {
384       DEBUG ("Connection disconnected or no reply to GetNameOwner(%s)",
385           context->name);
386     }
387   else if (dbus_message_get_type (context->reply) ==
388       DBUS_MESSAGE_TYPE_METHOD_RETURN)
389     {
390       if (dbus_message_get_args (context->reply, NULL,
391             DBUS_TYPE_STRING, &owner,
392             DBUS_TYPE_INVALID))
393         {
394           DEBUG ("GetNameOwner(%s) -> %s", context->name, owner);
395         }
396       else
397         {
398           DEBUG ("Malformed reply from GetNameOwner(%s), assuming no owner",
399               context->name);
400         }
401     }
402   else
403     {
404       if (DEBUGGING)
405         {
406           DBusError error = DBUS_ERROR_INIT;
407 
408           if (dbus_set_error_from_message (&error, context->reply))
409             {
410               DEBUG ("GetNameOwner(%s) raised %s: %s", context->name,
411                   error.name, error.message);
412               dbus_error_free (&error);
413             }
414           else
415             {
416               DEBUG ("Unexpected message type from GetNameOwner(%s)",
417                   context->name);
418             }
419         }
420     }
421 
422   _tp_dbus_daemon_name_owner_changed (context->self, context->name, owner);
423 
424   return FALSE;
425 }
426 
427 /**
428  * TpDBusDaemonNameOwnerChangedCb:
429  * @bus_daemon: The D-Bus daemon
430  * @name: The name whose ownership has changed or been discovered
431  * @new_owner: The unique name that now owns @name
432  * @user_data: Arbitrary user-supplied data as passed to
433  *  tp_dbus_daemon_watch_name_owner()
434  *
435  * The signature of the callback called by tp_dbus_daemon_watch_name_owner().
436  *
437  * Since: 0.7.1
438  */
439 
440 static inline gchar *
_tp_dbus_daemon_get_noc_rule(const gchar * name)441 _tp_dbus_daemon_get_noc_rule (const gchar *name)
442 {
443   return g_strdup_printf ("type='signal',"
444       "sender='" DBUS_SERVICE_DBUS "',"
445       "path='" DBUS_PATH_DBUS "',"
446       "interface='"DBUS_INTERFACE_DBUS "',"
447       "member='NameOwnerChanged',"
448       "arg0='%s'", name);
449 }
450 
451 static void
_tp_dbus_daemon_get_name_owner_notify(DBusPendingCall * pc,gpointer data)452 _tp_dbus_daemon_get_name_owner_notify (DBusPendingCall *pc,
453                                        gpointer data)
454 {
455   GetNameOwnerContext *context = data;
456 
457   /* we recycle this function for the case where the connection is already
458    * disconnected: in that case we use pc = NULL */
459   if (pc != NULL)
460     context->reply = dbus_pending_call_steal_reply (pc);
461 
462   /* We have to do the real work in an idle, so we don't break re-entrant
463    * calls (the dbus-glib event source isn't re-entrant) */
464   context->refs++;
465   g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_get_name_owner_idle,
466       context, get_name_owner_context_unref);
467 
468   if (pc != NULL)
469     dbus_pending_call_unref (pc);
470 }
471 
472 /**
473  * tp_dbus_daemon_watch_name_owner:
474  * @self: The D-Bus daemon
475  * @name: The name whose ownership is to be watched
476  * @callback: Callback to call when the ownership is discovered or changes
477  * @user_data: Arbitrary data to pass to @callback
478  * @destroy: Called to destroy @user_data when the name owner watch is
479  *  cancelled due to tp_dbus_daemon_cancel_name_owner_watch()
480  *
481  * Arrange for @callback to be called with the owner of @name as soon as
482  * possible (which might even be before this function returns!), then
483  * again every time the ownership of @name changes.
484  *
485  * If multiple watches are registered for the same @name, they will be called
486  * in the order they were registered.
487  *
488  * Since: 0.7.1
489  */
490 void
tp_dbus_daemon_watch_name_owner(TpDBusDaemon * self,const gchar * name,TpDBusDaemonNameOwnerChangedCb callback,gpointer user_data,GDestroyNotify destroy)491 tp_dbus_daemon_watch_name_owner (TpDBusDaemon *self,
492                                  const gchar *name,
493                                  TpDBusDaemonNameOwnerChangedCb callback,
494                                  gpointer user_data,
495                                  GDestroyNotify destroy)
496 {
497   _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
498       name);
499   _NameOwnerSubWatch tmp = { callback, user_data, destroy };
500 
501   g_return_if_fail (TP_IS_DBUS_DAEMON (self));
502   g_return_if_fail (tp_dbus_check_valid_bus_name (name,
503         TP_DBUS_NAME_TYPE_ANY, NULL));
504   g_return_if_fail (callback != NULL);
505 
506   if (watch == NULL)
507     {
508       gchar *match_rule;
509       DBusMessage *message;
510       DBusPendingCall *pc = NULL;
511       GetNameOwnerContext *context = get_name_owner_context_new (self, name);
512 
513       /* Allocate a new watch */
514       watch = g_slice_new0 (_NameOwnerWatch);
515       watch->last_owner = NULL;
516       watch->callbacks = g_array_new (FALSE, FALSE,
517           sizeof (_NameOwnerSubWatch));
518 
519       g_hash_table_insert (self->priv->name_owner_watches, g_strdup (name),
520           watch);
521 
522       /* We want to be notified about name owner changes for this one.
523        * Assume the match addition will succeed; there's no good way to cope
524        * with failure here... */
525       match_rule = _tp_dbus_daemon_get_noc_rule (name);
526       DEBUG ("Adding match rule %s", match_rule);
527       dbus_bus_add_match (self->priv->libdbus, match_rule, NULL);
528       g_free (match_rule);
529 
530       message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
531           DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
532 
533       if (message == NULL)
534         ERROR ("Out of memory");
535 
536       /* We already checked that @name was in (a small subset of) UTF-8,
537        * so OOM is the only thing that can go wrong. The use of &name here
538        * is because libdbus is strange. */
539       if (!dbus_message_append_args (message,
540             DBUS_TYPE_STRING, &name,
541             DBUS_TYPE_INVALID))
542         ERROR ("Out of memory");
543 
544       if (!dbus_connection_send_with_reply (self->priv->libdbus,
545           message, &pc, -1))
546         ERROR ("Out of memory");
547       /* pc is unreffed by _tp_dbus_daemon_get_name_owner_notify */
548       dbus_message_unref (message);
549 
550       if (pc == NULL || dbus_pending_call_get_completed (pc))
551         {
552           /* pc can be NULL when the connection is already disconnected */
553           _tp_dbus_daemon_get_name_owner_notify (pc, context);
554           get_name_owner_context_unref (context);
555         }
556       else if (!dbus_pending_call_set_notify (pc,
557             _tp_dbus_daemon_get_name_owner_notify,
558             context, get_name_owner_context_unref))
559         {
560           ERROR ("Out of memory");
561         }
562     }
563 
564   g_array_append_val (watch->callbacks, tmp);
565 
566   if (watch->last_owner != NULL)
567     {
568       /* FIXME: should avoid reentrancy? */
569       callback (self, name, watch->last_owner, user_data);
570     }
571 }
572 
573 static void
_tp_dbus_daemon_stop_watching(TpDBusDaemon * self,const gchar * name,_NameOwnerWatch * watch)574 _tp_dbus_daemon_stop_watching (TpDBusDaemon *self,
575                                const gchar *name,
576                                _NameOwnerWatch *watch)
577 {
578   gchar *match_rule;
579 
580   /* Clean up any leftöver callbacks. */
581   if (watch->callbacks->len > 0)
582     {
583       guint i;
584 
585       for (i = 0; i < watch->callbacks->len; i++)
586         {
587           _NameOwnerSubWatch *entry = &g_array_index (watch->callbacks,
588               _NameOwnerSubWatch, i);
589 
590           if (entry->destroy != NULL)
591             entry->destroy (entry->user_data);
592         }
593     }
594 
595   g_array_unref (watch->callbacks);
596   g_free (watch->last_owner);
597   g_slice_free (_NameOwnerWatch, watch);
598 
599   match_rule = _tp_dbus_daemon_get_noc_rule (name);
600   DEBUG ("Removing match rule %s", match_rule);
601   dbus_bus_remove_match (self->priv->libdbus, match_rule, NULL);
602   g_free (match_rule);
603 }
604 
605 /**
606  * tp_dbus_daemon_cancel_name_owner_watch: (skip)
607  * @self: the D-Bus daemon
608  * @name: the name that was being watched
609  * @callback: the callback that was called
610  * @user_data: the user data that was provided
611  *
612  * If there was a previous call to tp_dbus_daemon_watch_name_owner()
613  * with exactly the given @name, @callback and @user_data, remove it.
614  *
615  * If more than one watch matching the details provided was active, remove
616  * only the most recently added one.
617  *
618  * Returns: %TRUE if there was such a watch, %FALSE otherwise
619  *
620  * Since: 0.7.1
621  */
622 gboolean
tp_dbus_daemon_cancel_name_owner_watch(TpDBusDaemon * self,const gchar * name,TpDBusDaemonNameOwnerChangedCb callback,gconstpointer user_data)623 tp_dbus_daemon_cancel_name_owner_watch (TpDBusDaemon *self,
624                                         const gchar *name,
625                                         TpDBusDaemonNameOwnerChangedCb callback,
626                                         gconstpointer user_data)
627 {
628   _NameOwnerWatch *watch = g_hash_table_lookup (self->priv->name_owner_watches,
629       name);
630 
631   g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
632   g_return_val_if_fail (name != NULL, FALSE);
633   g_return_val_if_fail (callback != NULL, FALSE);
634 
635   if (watch != NULL)
636     {
637       /* Check to see whether this (callback, user_data) pair is in the watch's
638        * array of callbacks. */
639       GArray *array = watch->callbacks;
640       /* 1 greater than an index into @array, to avoid it going negative;
641        * we iterate in reverse to have "last in = first out" as documented. */
642       guint i;
643 
644       for (i = array->len; i > 0; i--)
645         {
646           _NameOwnerSubWatch *entry = &g_array_index (array,
647               _NameOwnerSubWatch, i - 1);
648 
649           if (entry->callback == callback && entry->user_data == user_data)
650             {
651               entry->callback = NULL;
652               tp_dbus_daemon_maybe_free_name_owner_watch (self, name, watch);
653               return TRUE;
654             }
655         }
656     }
657 
658   /* We haven't found it */
659   return FALSE;
660 }
661 
662 /* for internal use (TpChannel, TpConnection _new convenience functions) */
663 gboolean
_tp_dbus_daemon_get_name_owner(TpDBusDaemon * self,gint timeout_ms,const gchar * well_known_name,gchar ** unique_name,GError ** error)664 _tp_dbus_daemon_get_name_owner (TpDBusDaemon *self,
665                                 gint timeout_ms,
666                                 const gchar *well_known_name,
667                                 gchar **unique_name,
668                                 GError **error)
669 {
670   DBusGConnection *gconn;
671   DBusConnection *dbc;
672   DBusMessage *message;
673   DBusMessage *reply;
674   DBusError dbus_error;
675   const char *name_in_reply;
676   const GError *invalidated;
677 
678   g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
679   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
680 
681   invalidated = tp_proxy_get_invalidated (self);
682 
683   if (invalidated != NULL)
684     {
685       if (error != NULL)
686         *error = g_error_copy (invalidated);
687 
688       return FALSE;
689     }
690 
691   gconn = tp_proxy_get_dbus_connection (self);
692   dbc = dbus_g_connection_get_connection (gconn);
693 
694   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
695       DBUS_INTERFACE_DBUS, "GetNameOwner");
696 
697   if (message == NULL)
698     ERROR ("Out of memory");
699 
700   if (!dbus_message_append_args (message,
701         DBUS_TYPE_STRING, &well_known_name,
702         DBUS_TYPE_INVALID))
703     ERROR ("Out of memory");
704 
705   dbus_error_init (&dbus_error);
706   reply = dbus_connection_send_with_reply_and_block (dbc, message,
707       timeout_ms, &dbus_error);
708 
709   dbus_message_unref (message);
710 
711   if (reply == NULL)
712     {
713       if (!tp_strdiff (dbus_error.name, DBUS_ERROR_NO_MEMORY))
714         ERROR ("Out of memory");
715 
716       /* FIXME: ideally we'd use dbus-glib's error mapping for this */
717       g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
718           "%s: %s", dbus_error.name, dbus_error.message);
719 
720       dbus_error_free (&dbus_error);
721       return FALSE;
722     }
723 
724   if (!dbus_message_get_args (reply, &dbus_error,
725         DBUS_TYPE_STRING, &name_in_reply,
726         DBUS_TYPE_INVALID))
727     {
728       g_set_error (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_NAME_OWNER_LOST,
729           "%s: %s", dbus_error.name, dbus_error.message);
730 
731       dbus_error_free (&dbus_error);
732       dbus_message_unref (reply);
733       return FALSE;
734     }
735 
736   if (unique_name != NULL)
737     *unique_name = g_strdup (name_in_reply);
738 
739   dbus_message_unref (reply);
740 
741   return TRUE;
742 }
743 
744 /**
745  * tp_dbus_daemon_request_name:
746  * @self: a TpDBusDaemon
747  * @well_known_name: a well-known name to acquire
748  * @idempotent: whether to consider it to be a success if this process
749  *              already owns the name
750  * @error: used to raise an error if %FALSE is returned
751  *
752  * Claim the given well-known name without queueing, allowing replacement
753  * or replacing an existing name-owner. This makes a synchronous call to the
754  * bus daemon.
755  *
756  * Returns: %TRUE if @well_known_name was claimed, or %FALSE and sets @error if
757  *          an error occurred.
758  *
759  * Since: 0.7.30
760  */
761 gboolean
tp_dbus_daemon_request_name(TpDBusDaemon * self,const gchar * well_known_name,gboolean idempotent,GError ** error)762 tp_dbus_daemon_request_name (TpDBusDaemon *self,
763                              const gchar *well_known_name,
764                              gboolean idempotent,
765                              GError **error)
766 {
767   TpProxy *as_proxy = (TpProxy *) self;
768   DBusGConnection *gconn;
769   DBusConnection *dbc;
770   DBusError dbus_error;
771   int result;
772   const GError *invalidated;
773 
774   g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
775   g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
776         TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
777   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
778 
779   invalidated = tp_proxy_get_invalidated (self);
780 
781   if (invalidated != NULL)
782     {
783       if (error != NULL)
784         *error = g_error_copy (invalidated);
785 
786       return FALSE;
787     }
788 
789   gconn = as_proxy->dbus_connection;
790   dbc = dbus_g_connection_get_connection (gconn);
791 
792   dbus_error_init (&dbus_error);
793   result = dbus_bus_request_name (dbc, well_known_name,
794       DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);
795 
796   switch (result)
797     {
798     case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
799       return TRUE;
800 
801     case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
802       if (idempotent)
803         {
804           return TRUE;
805         }
806       else
807         {
808           g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
809               "Name '%s' already in use by this process", well_known_name);
810           return FALSE;
811         }
812 
813     case DBUS_REQUEST_NAME_REPLY_EXISTS:
814     case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
815       /* the latter shouldn't actually happen since we said DO_NOT_QUEUE */
816       g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
817           "Name '%s' already in use by another process", well_known_name);
818       return FALSE;
819 
820     case -1:
821       g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
822           "%s: %s", dbus_error.name, dbus_error.message);
823       dbus_error_free (&dbus_error);
824       return FALSE;
825 
826     default:
827       g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
828           "RequestName('%s') returned %d and I don't know what that means",
829           well_known_name, result);
830       return FALSE;
831     }
832 }
833 
834 /**
835  * tp_dbus_daemon_release_name:
836  * @self: a TpDBusDaemon
837  * @well_known_name: a well-known name owned by this process to release
838  * @error: used to raise an error if %FALSE is returned
839  *
840  * Release the given well-known name. This makes a synchronous call to the bus
841  * daemon.
842  *
843  * Returns: %TRUE if @well_known_name was released, or %FALSE and sets @error
844  *          if an error occurred.
845  *
846  * Since: 0.7.30
847  */
848 gboolean
tp_dbus_daemon_release_name(TpDBusDaemon * self,const gchar * well_known_name,GError ** error)849 tp_dbus_daemon_release_name (TpDBusDaemon *self,
850                              const gchar *well_known_name,
851                              GError **error)
852 {
853   TpProxy *as_proxy = (TpProxy *) self;
854   DBusGConnection *gconn;
855   DBusConnection *dbc;
856   DBusError dbus_error;
857   int result;
858   const GError *invalidated;
859 
860   g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), FALSE);
861   g_return_val_if_fail (tp_dbus_check_valid_bus_name (well_known_name,
862         TP_DBUS_NAME_TYPE_WELL_KNOWN, error), FALSE);
863   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
864 
865   invalidated = tp_proxy_get_invalidated (self);
866 
867   if (invalidated != NULL)
868     {
869       if (error != NULL)
870         *error = g_error_copy (invalidated);
871 
872       return FALSE;
873     }
874 
875   gconn = as_proxy->dbus_connection;
876   dbc = dbus_g_connection_get_connection (gconn);
877   dbus_error_init (&dbus_error);
878   result = dbus_bus_release_name (dbc, well_known_name, &dbus_error);
879 
880   switch (result)
881     {
882     case DBUS_RELEASE_NAME_REPLY_RELEASED:
883       return TRUE;
884 
885     case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
886       g_set_error (error, TP_ERROR, TP_ERROR_NOT_YOURS,
887           "Name '%s' owned by another process", well_known_name);
888       return FALSE;
889 
890     case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
891       g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
892           "Name '%s' not owned", well_known_name);
893       return FALSE;
894 
895     case -1:
896       g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
897           "%s: %s", dbus_error.name, dbus_error.message);
898       dbus_error_free (&dbus_error);
899       return FALSE;
900 
901     default:
902       g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
903           "ReleaseName('%s') returned %d and I don't know what that means",
904           well_known_name, result);
905       return FALSE;
906     }
907 }
908 
909 /**
910  * tp_dbus_daemon_register_object:
911  * @self: object representing a connection to a bus
912  * @object_path: an object path
913  * @object: (type GObject.Object) (transfer none): an object to export
914  *
915  * Export @object at @object_path. This is a convenience wrapper around
916  * dbus_g_connection_register_g_object(), and behaves similarly.
917  *
918  * Since: 0.11.3
919  */
920 void
tp_dbus_daemon_register_object(TpDBusDaemon * self,const gchar * object_path,gpointer object)921 tp_dbus_daemon_register_object (TpDBusDaemon *self,
922     const gchar *object_path,
923     gpointer object)
924 {
925   TpProxy *as_proxy = (TpProxy *) self;
926 
927   g_return_if_fail (TP_IS_DBUS_DAEMON (self));
928   g_return_if_fail (tp_dbus_check_valid_object_path (object_path, NULL));
929   g_return_if_fail (G_IS_OBJECT (object));
930 
931   dbus_g_connection_register_g_object (as_proxy->dbus_connection,
932       object_path, object);
933 }
934 
935 /**
936  * tp_dbus_daemon_unregister_object:
937  * @self: object representing a connection to a bus
938  * @object: (type GObject.Object) (transfer none): an object previously exported
939  * with tp_dbus_daemon_register_object()
940  *
941  * Stop exporting @object on D-Bus. This is a convenience wrapper around
942  * dbus_g_connection_unregister_g_object(), and behaves similarly.
943  *
944  * Since: 0.11.3
945  */
946 void
tp_dbus_daemon_unregister_object(TpDBusDaemon * self,gpointer object)947 tp_dbus_daemon_unregister_object (TpDBusDaemon *self,
948     gpointer object)
949 {
950   TpProxy *as_proxy = (TpProxy *) self;
951 
952   g_return_if_fail (TP_IS_DBUS_DAEMON (self));
953   g_return_if_fail (G_IS_OBJECT (object));
954 
955   dbus_g_connection_unregister_g_object (as_proxy->dbus_connection, object);
956 }
957 
958 /**
959  * tp_dbus_daemon_get_unique_name:
960  * @self: object representing a connection to a bus
961  *
962  * <!-- Returns: is enough -->
963  *
964  * Returns: the unique name of this connection to the bus, which is valid for
965  *  as long as this #TpDBusDaemon is
966  * Since: 0.7.35
967  */
968 const gchar *
tp_dbus_daemon_get_unique_name(TpDBusDaemon * self)969 tp_dbus_daemon_get_unique_name (TpDBusDaemon *self)
970 {
971   g_return_val_if_fail (TP_IS_DBUS_DAEMON (self), NULL);
972 
973   return dbus_bus_get_unique_name (self->priv->libdbus);
974 }
975 
976 typedef struct {
977     TpDBusDaemon *self;
978     DBusMessage *reply;
979     TpDBusDaemonListNamesCb callback;
980     gpointer user_data;
981     GDestroyNotify destroy;
982     gpointer weak_object;
983     gsize refs;
984 } ListNamesContext;
985 
986 static ListNamesContext *
list_names_context_new(TpDBusDaemon * self,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)987 list_names_context_new (TpDBusDaemon *self,
988     TpDBusDaemonListNamesCb callback,
989     gpointer user_data,
990     GDestroyNotify destroy,
991     GObject *weak_object)
992 {
993   ListNamesContext *context = g_slice_new (ListNamesContext);
994 
995   context->self = g_object_ref (self);
996   context->reply = NULL;
997   context->callback = callback;
998   context->user_data = user_data;
999   context->destroy = destroy;
1000   context->weak_object = weak_object;
1001 
1002   if (context->weak_object != NULL)
1003     g_object_add_weak_pointer (weak_object, &context->weak_object);
1004 
1005   context->refs = 1;
1006   return context;
1007 }
1008 
1009 static void
list_names_context_unref(gpointer data)1010 list_names_context_unref (gpointer data)
1011 {
1012   ListNamesContext *context = data;
1013 
1014   if (--context->refs == 0)
1015     {
1016       g_object_unref (context->self);
1017 
1018       if (context->reply != NULL)
1019         dbus_message_unref (context->reply);
1020 
1021       if (context->destroy != NULL)
1022         context->destroy (context->user_data);
1023 
1024       context->destroy = NULL;
1025 
1026       if (context->weak_object != NULL)
1027         g_object_remove_weak_pointer (context->weak_object,
1028             &context->weak_object);
1029 
1030       g_slice_free (ListNamesContext, context);
1031     }
1032 }
1033 
1034 static gboolean
_tp_dbus_daemon_list_names_idle(gpointer data)1035 _tp_dbus_daemon_list_names_idle (gpointer data)
1036 {
1037   ListNamesContext *context = data;
1038   char **array = NULL;
1039   const gchar * const *result = NULL;
1040   GError *error = NULL;
1041 
1042   if (context->callback == NULL)
1043     {
1044       DEBUG ("Caller no longer cares (weak object vanished), ignoring");
1045       return FALSE;
1046     }
1047 
1048   if (context->reply == NULL)
1049     {
1050       g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_DISCONNECTED,
1051           "DBusConnection disconnected");
1052     }
1053   else if (dbus_message_get_type (context->reply) ==
1054       DBUS_MESSAGE_TYPE_METHOD_RETURN)
1055     {
1056       int n_elements;
1057 
1058       if (dbus_message_get_args (context->reply, NULL,
1059             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &n_elements,
1060             DBUS_TYPE_INVALID))
1061         {
1062           result = (const gchar * const *) array;
1063           g_assert (result[n_elements] == NULL);
1064         }
1065       else
1066         {
1067           g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS,
1068               "Malformed reply from List*Names()");
1069         }
1070     }
1071   else
1072     {
1073       DBusError dbus_error = DBUS_ERROR_INIT;
1074 
1075       if (dbus_set_error_from_message (&dbus_error, context->reply))
1076         {
1077           /* FIXME: ideally we'd use dbus-glib's error mapping here, but we
1078            * don't have access to it */
1079           g_set_error (&error, DBUS_GERROR, DBUS_GERROR_FAILED,
1080               "List*Names() raised %s: %s", dbus_error.name,
1081               dbus_error.message);
1082           dbus_error_free (&dbus_error);
1083         }
1084       else
1085         {
1086           g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS,
1087               "Unexpected message type from List*Names()");
1088         }
1089     }
1090 
1091   if (error != NULL)
1092     DEBUG ("%s", error->message);
1093 
1094   context->callback (context->self, result, error, context->user_data,
1095       context->weak_object);
1096   dbus_free_string_array (array);   /* NULL-safe */
1097   return FALSE;
1098 }
1099 
1100 static void
_tp_dbus_daemon_list_names_notify(DBusPendingCall * pc,gpointer data)1101 _tp_dbus_daemon_list_names_notify (DBusPendingCall *pc,
1102                                    gpointer data)
1103 {
1104   ListNamesContext *context = data;
1105 
1106   /* we recycle this function for the case where the connection is already
1107    * disconnected: in that case we use pc = NULL */
1108   if (pc != NULL)
1109     context->reply = dbus_pending_call_steal_reply (pc);
1110 
1111   /* We have to do the real work in an idle, so we don't break re-entrant
1112    * calls (the dbus-glib event source isn't re-entrant) */
1113   context->refs++;
1114   g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_list_names_idle,
1115       context, list_names_context_unref);
1116 
1117   if (pc != NULL)
1118     dbus_pending_call_unref (pc);
1119 }
1120 
1121 /**
1122  * TpDBusDaemonListNamesCb:
1123  * @bus_daemon: object representing a connection to a bus
1124  * @names: constant %NULL-terminated array of constant strings representing
1125  *  bus names, or %NULL on error
1126  * @error: the error that occurred, or %NULL on success
1127  * @user_data: the same user data that was passed to
1128  *  tp_dbus_daemon_list_names or tp_dbus_daemon_list_activatable_names
1129  * @weak_object: the same object that was passed to
1130  *  tp_dbus_daemon_list_names or tp_dbus_daemon_list_activatable_names
1131  *
1132  * Signature of a callback for functions that list bus names.
1133  *
1134  * Since: 0.7.35
1135  */
1136 
1137 static void
_tp_dbus_daemon_list_names_common(TpDBusDaemon * self,const gchar * method,gint timeout_ms,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)1138 _tp_dbus_daemon_list_names_common (TpDBusDaemon *self,
1139     const gchar *method,
1140     gint timeout_ms,
1141     TpDBusDaemonListNamesCb callback,
1142     gpointer user_data,
1143     GDestroyNotify destroy,
1144     GObject *weak_object)
1145 {
1146   DBusMessage *message;
1147   DBusPendingCall *pc = NULL;
1148   ListNamesContext *context;
1149 
1150   g_return_if_fail (TP_IS_DBUS_DAEMON (self));
1151   g_return_if_fail (callback != NULL);
1152   g_return_if_fail (weak_object == NULL || G_IS_OBJECT (weak_object));
1153 
1154   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
1155       DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, method);
1156 
1157   if (message == NULL)
1158     ERROR ("Out of memory");
1159 
1160   if (!dbus_connection_send_with_reply (self->priv->libdbus,
1161       message, &pc, timeout_ms))
1162     ERROR ("Out of memory");
1163   /* pc is unreffed by _tp_dbus_daemon_list_names_notify */
1164   dbus_message_unref (message);
1165 
1166   context = list_names_context_new (self, callback, user_data, destroy,
1167     weak_object);
1168 
1169   if (pc == NULL || dbus_pending_call_get_completed (pc))
1170     {
1171       /* pc can be NULL when the connection is already disconnected */
1172       _tp_dbus_daemon_list_names_notify (pc, context);
1173       list_names_context_unref (context);
1174     }
1175   else if (!dbus_pending_call_set_notify (pc,
1176         _tp_dbus_daemon_list_names_notify, context,
1177         list_names_context_unref))
1178     {
1179       ERROR ("Out of memory");
1180     }
1181 }
1182 
1183 /**
1184  * tp_dbus_daemon_list_names:
1185  * @self: object representing a connection to a bus
1186  * @timeout_ms: timeout for the call
1187  * @callback: callback to be called on success or failure; must not be %NULL
1188  * @user_data: opaque user-supplied data to pass to the callback
1189  * @destroy: if not %NULL, called with @user_data as argument after the call
1190  *  has succeeded or failed, or after @weak_object has been destroyed
1191  * @weak_object: if not %NULL, a GObject which will be weakly referenced; if
1192  *  it is destroyed, @callback will not be called at all
1193  *
1194  * Call the ListNames method on the bus daemon, asynchronously. The @callback
1195  * will be called from the main loop with a list of all the names (either
1196  * unique or well-known) that exist on the bus.
1197  *
1198  * In versions of telepathy-glib that have it, this should be preferred
1199  * instead of calling tp_cli_dbus_daemon_call_list_names(), since that
1200  * function will result in wakeups for every NameOwnerChanged signal.
1201  *
1202  * Since: 0.7.35
1203  */
1204 void
tp_dbus_daemon_list_names(TpDBusDaemon * self,gint timeout_ms,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)1205 tp_dbus_daemon_list_names (TpDBusDaemon *self,
1206     gint timeout_ms,
1207     TpDBusDaemonListNamesCb callback,
1208     gpointer user_data,
1209     GDestroyNotify destroy,
1210     GObject *weak_object)
1211 {
1212   _tp_dbus_daemon_list_names_common (self, "ListNames", timeout_ms,
1213       callback, user_data, destroy, weak_object);
1214 }
1215 
1216 /**
1217  * tp_dbus_daemon_list_activatable_names:
1218  * @self: object representing a connection to a bus daemon
1219  * @timeout_ms: timeout for the call
1220  * @callback: callback to be called on success or failure; must not be %NULL
1221  * @user_data: opaque user-supplied data to pass to the callback
1222  * @destroy: if not %NULL, called with @user_data as argument after the call
1223  *  has succeeded or failed, or after @weak_object has been destroyed
1224  * @weak_object: if not %NULL, a GObject which will be weakly referenced; if
1225  *  it is destroyed, @callback will not be called at all
1226  *
1227  * Call the ListActivatableNames method on the bus daemon, asynchronously.
1228  * The @callback will be called from the main loop with a list of all the
1229  * well-known names that are available for service-activation on the bus.
1230  *
1231  * In versions of telepathy-glib that have it, this should be preferred
1232  * instead of calling tp_cli_dbus_daemon_call_list_activatable_names(), since
1233  * that function will result in wakeups for every NameOwnerChanged signal.
1234  *
1235  * Since: 0.7.35
1236  */
1237 void
tp_dbus_daemon_list_activatable_names(TpDBusDaemon * self,gint timeout_ms,TpDBusDaemonListNamesCb callback,gpointer user_data,GDestroyNotify destroy,GObject * weak_object)1238 tp_dbus_daemon_list_activatable_names (TpDBusDaemon *self,
1239     gint timeout_ms,
1240     TpDBusDaemonListNamesCb callback,
1241     gpointer user_data,
1242     GDestroyNotify destroy,
1243     GObject *weak_object)
1244 {
1245   _tp_dbus_daemon_list_names_common (self, "ListActivatableNames", timeout_ms,
1246       callback, user_data, destroy, weak_object);
1247 }
1248 
1249 static void
free_daemon_list(gpointer p)1250 free_daemon_list (gpointer p)
1251 {
1252   GSList **slistp = p;
1253 
1254   g_slist_free (*slistp);
1255   g_slice_free (GSList *, slistp);
1256 }
1257 
1258 /* If you add more slice-allocation in this function, make the suppression
1259  * "tp_dbus_daemon_constructor @daemons once per DBusConnection" in
1260  * telepathy-glib.supp more specific. */
1261 static GObject *
tp_dbus_daemon_constructor(GType type,guint n_params,GObjectConstructParam * params)1262 tp_dbus_daemon_constructor (GType type,
1263                             guint n_params,
1264                             GObjectConstructParam *params)
1265 {
1266   GObjectClass *object_class =
1267       (GObjectClass *) tp_dbus_daemon_parent_class;
1268   TpDBusDaemon *self = TP_DBUS_DAEMON (object_class->constructor (type,
1269         n_params, params));
1270   TpProxy *as_proxy = (TpProxy *) self;
1271   GSList **daemons;
1272 
1273   g_assert (!tp_strdiff (as_proxy->bus_name, DBUS_SERVICE_DBUS));
1274   g_assert (!tp_strdiff (as_proxy->object_path, DBUS_PATH_DBUS));
1275 
1276   self->priv->libdbus = dbus_connection_ref (
1277       dbus_g_connection_get_connection (
1278         tp_proxy_get_dbus_connection (self)));
1279 
1280   /* one ref per TpDBusDaemon, released in finalize */
1281   if (!dbus_connection_allocate_data_slot (&daemons_slot))
1282     ERROR ("Out of memory");
1283 
1284   daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
1285 
1286   if (daemons == NULL)
1287     {
1288       /* This slice is never freed; it's a one-per-DBusConnection leak. */
1289       daemons = g_slice_new (GSList *);
1290 
1291       *daemons = NULL;
1292       dbus_connection_set_data (self->priv->libdbus, daemons_slot, daemons,
1293           free_daemon_list);
1294 
1295       /* we add this filter at most once per DBusConnection */
1296       if (!dbus_connection_add_filter (self->priv->libdbus,
1297             _tp_dbus_daemon_name_owner_changed_filter, NULL, NULL))
1298         ERROR ("Out of memory");
1299     }
1300 
1301   *daemons = g_slist_prepend (*daemons, self);
1302 
1303   return (GObject *) self;
1304 }
1305 
1306 static void
tp_dbus_daemon_init(TpDBusDaemon * self)1307 tp_dbus_daemon_init (TpDBusDaemon *self)
1308 {
1309   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_DBUS_DAEMON,
1310       TpDBusDaemonPrivate);
1311 
1312   self->priv->name_owner_watches = g_hash_table_new_full (g_str_hash,
1313       g_str_equal, g_free, NULL);
1314 }
1315 
1316 static void
tp_dbus_daemon_dispose(GObject * object)1317 tp_dbus_daemon_dispose (GObject *object)
1318 {
1319   TpDBusDaemon *self = TP_DBUS_DAEMON (object);
1320   GSList **daemons;
1321 
1322   if (self->priv->name_owner_watches != NULL)
1323     {
1324       GHashTable *tmp = self->priv->name_owner_watches;
1325       GHashTableIter iter;
1326       gpointer k, v;
1327 
1328       self->priv->name_owner_watches = NULL;
1329       g_hash_table_iter_init (&iter, tmp);
1330 
1331       while (g_hash_table_iter_next (&iter, &k, &v))
1332         {
1333           _NameOwnerWatch *watch = v;
1334 
1335           /* it refs us while invoking stuff */
1336           g_assert (watch->invoking == 0);
1337           _tp_dbus_daemon_stop_watching (self, k, watch);
1338           g_hash_table_iter_remove (&iter);
1339         }
1340 
1341       g_hash_table_unref (tmp);
1342     }
1343 
1344   if (self->priv->libdbus != NULL)
1345     {
1346       /* remove myself from the list to be notified on NoC */
1347       daemons = dbus_connection_get_data (self->priv->libdbus, daemons_slot);
1348 
1349       /* should always be non-NULL, barring bugs */
1350       if (G_LIKELY (daemons != NULL))
1351         {
1352           *daemons = g_slist_remove (*daemons, self);
1353 
1354           if (*daemons == NULL)
1355             {
1356               /* this results in a call to free_daemon_list (daemons) */
1357               dbus_connection_set_data (self->priv->libdbus, daemons_slot,
1358                   NULL, NULL);
1359             }
1360         }
1361 
1362       dbus_connection_unref (self->priv->libdbus);
1363       self->priv->libdbus = NULL;
1364     }
1365 
1366   G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->dispose (object);
1367 }
1368 
1369 static void
tp_dbus_daemon_finalize(GObject * object)1370 tp_dbus_daemon_finalize (GObject *object)
1371 {
1372   GObjectFinalizeFunc chain_up = G_OBJECT_CLASS (tp_dbus_daemon_parent_class)->finalize;
1373 
1374   /* one ref per TpDBusDaemon, from constructor */
1375   dbus_connection_free_data_slot (&daemons_slot);
1376 
1377   if (chain_up != NULL)
1378     chain_up (object);
1379 }
1380 
1381 /**
1382  * tp_dbus_daemon_init_known_interfaces:
1383  *
1384  * Ensure that the known interfaces for TpDBusDaemon have been set up.
1385  * This is done automatically when necessary, but for correct
1386  * overriding of library interfaces by local extensions, you should
1387  * call this function before calling
1388  * tp_proxy_or_subclass_hook_on_interface_add() with first argument
1389  * %TP_TYPE_DBUS_DAEMON.
1390  *
1391  * Since: 0.7.32
1392  */
1393 void
tp_dbus_daemon_init_known_interfaces(void)1394 tp_dbus_daemon_init_known_interfaces (void)
1395 {
1396   static gsize once = 0;
1397 
1398   if (g_once_init_enter (&once))
1399     {
1400       tp_proxy_init_known_interfaces ();
1401       tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_DBUS_DAEMON,
1402           tp_cli_dbus_daemon_add_signals);
1403 
1404       g_once_init_leave (&once, 1);
1405     }
1406 }
1407 
1408 static void
tp_dbus_daemon_class_init(TpDBusDaemonClass * klass)1409 tp_dbus_daemon_class_init (TpDBusDaemonClass *klass)
1410 {
1411   TpProxyClass *proxy_class = (TpProxyClass *) klass;
1412   GObjectClass *object_class = (GObjectClass *) klass;
1413 
1414   tp_dbus_daemon_init_known_interfaces ();
1415 
1416   g_type_class_add_private (klass, sizeof (TpDBusDaemonPrivate));
1417 
1418   object_class->constructor = tp_dbus_daemon_constructor;
1419   object_class->dispose = tp_dbus_daemon_dispose;
1420   object_class->finalize = tp_dbus_daemon_finalize;
1421 
1422   proxy_class->interface = TP_IFACE_QUARK_DBUS_DAEMON;
1423 }
1424 
1425 gboolean
_tp_dbus_daemon_is_the_shared_one(TpDBusDaemon * self)1426 _tp_dbus_daemon_is_the_shared_one (TpDBusDaemon *self)
1427 {
1428   return (self != NULL && self == starter_bus_daemon);
1429 }
1430 
1431 /* Auto-generated implementation of _tp_register_dbus_glib_marshallers */
1432 #include "_gen/register-dbus-glib-marshallers-body.h"
1433