1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gproxy.c Proxy for remote objects
3  *
4  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
5  * Copyright (C) 2005 Nokia
6  *
7  * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
8  *
9  * Licensed under the Academic Free License version 2.1
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  */
26 
27 #include <config.h>
28 
29 #include <dbus/dbus-glib.h>
30 #include <dbus/dbus-glib-lowlevel.h>
31 #include <dbus/dbus-signature.h>
32 #include "dbus-gutils.h"
33 #include "dbus-gsignature.h"
34 #include "dbus-gvalue.h"
35 #include "dbus-gvalue-utils.h"
36 #include "dbus-gobject.h"
37 #include <string.h>
38 #include <gobject/gvaluecollector.h>
39 #include <gio/gio.h>
40 
41 #define DBUS_G_PROXY_CALL_TO_ID(x) (GPOINTER_TO_UINT(x))
42 #define DBUS_G_PROXY_ID_TO_CALL(x) (GUINT_TO_POINTER(x))
43 #define DBUS_G_PROXY_GET_PRIVATE(o)  \
44        (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUS_TYPE_G_PROXY, DBusGProxyPrivate))
45 
46 static void oom (void) G_GNUC_NORETURN;
47 static void
oom(void)48 oom (void)
49 {
50   g_error ("no memory");
51 }
52 
53 typedef struct _DBusGProxyManager DBusGProxyManager;
54 
55 typedef struct _DBusGProxyPrivate DBusGProxyPrivate;
56 
57 struct _DBusGProxyPrivate
58 {
59   DBusGProxyManager *manager; /**< Proxy manager */
60   char *name;                 /**< Name messages go to or NULL */
61   char *path;                 /**< Path messages go to or NULL */
62   char *interface;            /**< Interface messages go to or NULL */
63 
64   DBusGProxyCall *name_call;  /**< Pending call id to retrieve name owner */
65   guint for_owner : 1;        /**< Whether or not this proxy is for a name owner */
66   guint associated : 1;       /**< Whether or not this proxy is associated (for name proxies) */
67 
68   /* FIXME: make threadsafe? */
69   guint call_id_counter;      /**< Integer counter for pending calls */
70 
71   GData *signal_signatures;   /**< D-BUS signatures for each signal */
72 
73   GHashTable *pending_calls;  /**< Calls made on this proxy which have not yet returned */
74 
75   int default_timeout; /**< Default timeout to use, see dbus_g_proxy_set_default_timeout */
76 };
77 
78 static void dbus_g_proxy_init               (DBusGProxy      *proxy);
79 static void dbus_g_proxy_class_init         (DBusGProxyClass *klass);
80 static GObject *dbus_g_proxy_constructor    (GType                  type,
81 					     guint                  n_construct_properties,
82 					     GObjectConstructParam *construct_properties);
83 static void     dbus_g_proxy_set_property       (GObject               *object,
84 						 guint                  prop_id,
85 						 const GValue          *value,
86 						 GParamSpec            *pspec);
87 static void     dbus_g_proxy_get_property       (GObject               *object,
88 						 guint                  prop_id,
89 						 GValue                *value,
90 						 GParamSpec            *pspec);
91 
92 static void dbus_g_proxy_finalize           (GObject         *object);
93 static void dbus_g_proxy_dispose            (GObject         *object);
94 static void dbus_g_proxy_destroy            (DBusGProxy      *proxy);
95 static void dbus_g_proxy_emit_remote_signal (DBusGProxy      *proxy,
96                                              DBusMessage     *message);
97 
98 static DBusGProxyCall *manager_begin_bus_call (DBusGProxyManager    *manager,
99 					       const char          *method,
100 					       DBusGProxyCallNotify notify,
101 					       gpointer             data,
102 					       GDestroyNotify       destroy,
103 					       GType                first_arg_type,
104 					       ...);
105 static guint dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
106 					       const char          *method,
107 					       DBusGProxyCallNotify notify,
108 					       gpointer             data,
109 					       GDestroyNotify       destroy,
110 					       GValueArray         *args,
111 					       int timeout );
112 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
113 						guint              call_id,
114 						GError           **error,
115 						GType              first_arg_type,
116 						va_list            args);
117 
118 /*
119  * A list of proxies with a given name+path+interface, used to
120  * route incoming signals.
121  */
122 typedef struct
123 {
124   GSList *proxies; /**< The list of proxies */
125 
126   char name[4]; /**< name (empty string for none), nul byte,
127                  *   path, nul byte,
128                  *   interface, nul byte
129                  */
130 
131 } DBusGProxyList;
132 
133 /*
134  * DBusGProxyManager's primary task is to route signals to the proxies
135  * those signals are emitted on. In order to do this it also has to
136  * track the owners of the names proxies are bound to.
137  */
138 struct _DBusGProxyManager
139 {
140   GStaticMutex lock; /**< Thread lock */
141   int refcount;      /**< Reference count */
142   DBusConnection *connection; /**< Connection we're associated with. */
143 
144   DBusGProxy *bus_proxy; /**< Special internal proxy used to talk to the bus */
145 
146   GHashTable *proxy_lists; /**< Hash used to route incoming signals
147                             *   and iterate over proxies
148                             *   tristring -> DBusGProxyList
149                             */
150   GHashTable *owner_match_rules; /**< Hash to keep track of match rules of
151                                   * NameOwnerChanged.
152                                   * gchar *name -> guint *refcount
153                             */
154   GHashTable *owner_names; /**< Hash to keep track of mapping from
155                             *   char *    -> GSList of DBusGProxyNameOwnerInfo
156 			    *   base name -> [name,name,...] for proxies which
157 			    *   are for names.
158 			    */
159   GSList *unassociated_proxies;     /**< List of name proxies for which
160 				     *   there was no result for
161 				     *   GetNameOwner
162 				     */
163 };
164 
165 static DBusGProxyManager *dbus_g_proxy_manager_ref    (DBusGProxyManager *manager);
166 static DBusHandlerResult  dbus_g_proxy_manager_filter (DBusConnection    *connection,
167                                                        DBusMessage       *message,
168                                                        void              *user_data);
169 
170 
171 /** Lock the DBusGProxyManager */
172 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
173 /** Unlock the DBusGProxyManager */
174 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
175 
176 static int g_proxy_manager_slot = -1;
177 
178 /* Lock controlling get/set manager as data on each connection */
179 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
180 
181 static DBusGProxyManager*
dbus_g_proxy_manager_get(DBusConnection * connection)182 dbus_g_proxy_manager_get (DBusConnection *connection)
183 {
184   DBusGProxyManager *manager;
185 
186   dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
187   if (g_proxy_manager_slot < 0)
188     g_error ("out of memory");
189 
190   g_static_mutex_lock (&connection_g_proxy_lock);
191 
192   manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
193   if (manager != NULL)
194     {
195       dbus_connection_free_data_slot (&g_proxy_manager_slot);
196       dbus_g_proxy_manager_ref (manager);
197       g_static_mutex_unlock (&connection_g_proxy_lock);
198       return manager;
199     }
200 
201   manager = g_new0 (DBusGProxyManager, 1);
202 
203   manager->refcount = 1;
204   manager->connection = connection;
205 
206   g_static_mutex_init (&manager->lock);
207 
208   /* Proxy managers keep the connection alive, which means that
209    * DBusGProxy indirectly does. To free a connection you have to free
210    * all the proxies referring to it.
211    */
212   dbus_connection_ref (manager->connection);
213 
214   dbus_connection_set_data (connection, g_proxy_manager_slot,
215                             manager, NULL);
216 
217   dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
218                               manager, NULL);
219 
220   g_static_mutex_unlock (&connection_g_proxy_lock);
221 
222   return manager;
223 }
224 
225 static DBusGProxyManager *
dbus_g_proxy_manager_ref(DBusGProxyManager * manager)226 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
227 {
228   g_assert (manager != NULL);
229   g_assert (manager->refcount > 0);
230 
231   LOCK_MANAGER (manager);
232 
233   manager->refcount += 1;
234 
235   UNLOCK_MANAGER (manager);
236 
237   return manager;
238 }
239 
240 static void
dbus_g_proxy_manager_unref(DBusGProxyManager * manager)241 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
242 {
243   g_assert (manager != NULL);
244   g_assert (manager->refcount > 0);
245 
246   LOCK_MANAGER (manager);
247   manager->refcount -= 1;
248   if (manager->refcount == 0)
249     {
250       UNLOCK_MANAGER (manager);
251 
252       if (manager->bus_proxy)
253 	g_object_unref (manager->bus_proxy);
254 
255       if (manager->proxy_lists)
256         {
257           /* can't have any proxies left since they hold
258            * a reference to the proxy manager.
259            */
260           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
261 
262           g_hash_table_destroy (manager->proxy_lists);
263           manager->proxy_lists = NULL;
264 
265         }
266 
267       if (manager->owner_match_rules)
268         {
269 	  /* Since we destroyed all proxies, none can be tracking
270 	   * name owners
271 	   */
272           g_assert (g_hash_table_size (manager->owner_match_rules) == 0);
273           g_hash_table_destroy (manager->owner_match_rules);
274           manager->owner_match_rules = NULL;
275         }
276 
277       if (manager->owner_names)
278 	{
279 	  /* Since we destroyed all proxies, none can be tracking
280 	   * name owners
281 	   */
282           g_assert (g_hash_table_size (manager->owner_names) == 0);
283 
284 	  g_hash_table_destroy (manager->owner_names);
285 	  manager->owner_names = NULL;
286 	}
287 
288       g_assert (manager->unassociated_proxies == NULL);
289 
290       g_static_mutex_free (&manager->lock);
291 
292       g_static_mutex_lock (&connection_g_proxy_lock);
293 
294       dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
295                                      manager);
296 
297       dbus_connection_set_data (manager->connection,
298                                 g_proxy_manager_slot,
299                                 NULL, NULL);
300 
301       g_static_mutex_unlock (&connection_g_proxy_lock);
302 
303       dbus_connection_unref (manager->connection);
304       g_free (manager);
305 
306       dbus_connection_free_data_slot (&g_proxy_manager_slot);
307     }
308   else
309     {
310       UNLOCK_MANAGER (manager);
311     }
312 }
313 
314 static guint
tristring_hash(gconstpointer key)315 tristring_hash (gconstpointer key)
316 {
317   const char *p = key;
318   guint h = *p;
319 
320   if (h)
321     {
322       for (p += 1; *p != '\0'; p++)
323         h = (h << 5) - h + *p;
324     }
325 
326   /* skip nul and do the next substring */
327   for (p += 1; *p != '\0'; p++)
328     h = (h << 5) - h + *p;
329 
330   /* skip nul again and another substring */
331   for (p += 1; *p != '\0'; p++)
332     h = (h << 5) - h + *p;
333 
334   return h;
335 }
336 
337 static gboolean
strequal_len(const char * a,const char * b,size_t * lenp)338 strequal_len (const char *a,
339               const char *b,
340               size_t     *lenp)
341 {
342   size_t a_len;
343   size_t b_len;
344 
345   a_len = strlen (a);
346   b_len = strlen (b);
347 
348   if (a_len != b_len)
349     return FALSE;
350 
351   if (memcmp (a, b, a_len) != 0)
352     return FALSE;
353 
354   *lenp = a_len;
355 
356   return TRUE;
357 }
358 
359 static gboolean
tristring_equal(gconstpointer a,gconstpointer b)360 tristring_equal (gconstpointer  a,
361                  gconstpointer  b)
362 {
363   const char *ap = a;
364   const char *bp = b;
365   size_t len;
366 
367   if (!strequal_len (ap, bp, &len))
368     return FALSE;
369 
370   ap += len + 1;
371   bp += len + 1;
372 
373   if (!strequal_len (ap, bp, &len))
374     return FALSE;
375 
376   ap += len + 1;
377   bp += len + 1;
378 
379   if (strcmp (ap, bp) != 0)
380     return FALSE;
381 
382   return TRUE;
383 }
384 
385 static char*
tristring_alloc_from_strings(size_t padding_before,const char * name,const char * path,const char * interface)386 tristring_alloc_from_strings (size_t      padding_before,
387                               const char *name,
388                               const char *path,
389                               const char *interface)
390 {
391   size_t name_len, iface_len, path_len, len;
392   char *tri;
393 
394   if (name)
395     name_len = strlen (name);
396   else
397     name_len = 0;
398 
399   path_len = strlen (path);
400 
401   iface_len = strlen (interface);
402 
403   tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
404 
405   len = padding_before;
406 
407   if (name)
408     memcpy (&tri[len], name, name_len);
409 
410   len += name_len;
411   tri[len] = '\0';
412   len += 1;
413 
414   g_assert (len == (padding_before + name_len + 1));
415 
416   memcpy (&tri[len], path, path_len);
417   len += path_len;
418   tri[len] = '\0';
419   len += 1;
420 
421   g_assert (len == (padding_before + name_len + path_len + 2));
422 
423   memcpy (&tri[len], interface, iface_len);
424   len += iface_len;
425   tri[len] = '\0';
426   len += 1;
427 
428   g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
429 
430   return tri;
431 }
432 
433 static char*
tristring_from_proxy(DBusGProxy * proxy)434 tristring_from_proxy (DBusGProxy *proxy)
435 {
436   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
437 
438   return tristring_alloc_from_strings (0,
439                                        priv->name,
440                                        priv->path,
441                                        priv->interface);
442 }
443 
444 static char*
tristring_from_message(DBusMessage * message)445 tristring_from_message (DBusMessage *message)
446 {
447   const char *path;
448   const char *interface;
449 
450   path = dbus_message_get_path (message);
451   interface = dbus_message_get_interface (message);
452 
453   g_assert (path);
454   g_assert (interface);
455 
456   return tristring_alloc_from_strings (0,
457                                        dbus_message_get_sender (message),
458                                        path, interface);
459 }
460 
461 static DBusGProxyList*
g_proxy_list_new(DBusGProxy * first_proxy)462 g_proxy_list_new (DBusGProxy *first_proxy)
463 {
464   DBusGProxyList *list;
465   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(first_proxy);
466 
467   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
468                                                priv->name,
469                                                priv->path,
470                                                priv->interface);
471   list->proxies = NULL;
472 
473   return list;
474 }
475 
476 static void
g_proxy_list_free(DBusGProxyList * list)477 g_proxy_list_free (DBusGProxyList *list)
478 {
479   /* we don't hold a reference to the proxies in the list,
480    * as they ref the GProxyManager
481    */
482   g_slist_free (list->proxies);
483 
484   g_free (list);
485 }
486 
487 static char*
g_proxy_get_signal_match_rule(DBusGProxy * proxy)488 g_proxy_get_signal_match_rule (DBusGProxy *proxy)
489 {
490   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
491   /* FIXME Escaping is required here */
492 
493   if (priv->name)
494     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
495                             priv->name, priv->path, priv->interface);
496   else
497     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
498                             priv->path, priv->interface);
499 }
500 
501 static char *
get_owner_match_rule(const gchar * name)502 get_owner_match_rule (const gchar *name)
503 {
504       return g_strdup_printf ("type='signal',sender='" DBUS_SERVICE_DBUS
505         "',path='" DBUS_PATH_DBUS
506         "',interface='" DBUS_INTERFACE_DBUS
507         "',member='NameOwnerChanged'"
508         ",arg0='%s'", name);
509 }
510 
511 typedef struct
512 {
513   char *name;
514   guint refcount;
515 } DBusGProxyNameOwnerInfo;
516 
517 static gint
find_name_in_info(gconstpointer a,gconstpointer b)518 find_name_in_info (gconstpointer a, gconstpointer b)
519 {
520   const DBusGProxyNameOwnerInfo *info = a;
521   const char *name = b;
522 
523   return strcmp (info->name, name);
524 }
525 
526 typedef struct
527 {
528   const char *name;
529   const char *owner;
530   DBusGProxyNameOwnerInfo *info;
531 } DBusGProxyNameOwnerForeachData;
532 
533 static void
name_owner_foreach(gpointer key,gpointer val,gpointer data)534 name_owner_foreach (gpointer key, gpointer val, gpointer data)
535 {
536   const char *owner;
537   DBusGProxyNameOwnerForeachData *foreach_data;
538   GSList *names;
539   GSList *link;
540 
541   owner = key;
542   names = val;
543   foreach_data = data;
544 
545   if (foreach_data->owner != NULL)
546     return;
547 
548   g_assert (foreach_data->info == NULL);
549 
550   link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
551   if (link)
552     {
553       foreach_data->owner = owner;
554       foreach_data->info = link->data;
555     }
556 }
557 
558 static gboolean
dbus_g_proxy_manager_lookup_name_owner(DBusGProxyManager * manager,const char * name,DBusGProxyNameOwnerInfo ** info,const char ** owner)559 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager        *manager,
560 					const char               *name,
561 					DBusGProxyNameOwnerInfo **info,
562 					const char              **owner)
563 {
564   DBusGProxyNameOwnerForeachData foreach_data;
565 
566   foreach_data.name = name;
567   foreach_data.owner = NULL;
568   foreach_data.info = NULL;
569 
570   g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
571 
572   *info = foreach_data.info;
573   *owner = foreach_data.owner;
574   return *info != NULL;
575 }
576 
577 static void
insert_nameinfo(DBusGProxyManager * manager,const char * owner,DBusGProxyNameOwnerInfo * info)578 insert_nameinfo (DBusGProxyManager       *manager,
579 		 const char              *owner,
580 		 DBusGProxyNameOwnerInfo *info)
581 {
582   GSList *names;
583   gboolean insert;
584 
585   names = g_hash_table_lookup (manager->owner_names, owner);
586 
587   /* Only need to g_hash_table_insert the first time */
588   insert = (names == NULL);
589 
590   names = g_slist_append (names, info);
591 
592   if (insert)
593     g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
594 }
595 
596 static void
dbus_g_proxy_manager_monitor_name_owner(DBusGProxyManager * manager,const char * owner,const char * name)597 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager  *manager,
598 					 const char         *owner,
599 					 const char         *name)
600 {
601   GSList *names;
602   GSList *link;
603   DBusGProxyNameOwnerInfo *nameinfo;
604 
605   names = g_hash_table_lookup (manager->owner_names, owner);
606   link = g_slist_find_custom (names, name, find_name_in_info);
607 
608   if (!link)
609     {
610       nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
611       nameinfo->name = g_strdup (name);
612       nameinfo->refcount = 1;
613 
614       insert_nameinfo (manager, owner, nameinfo);
615     }
616   else
617     {
618       nameinfo = link->data;
619       nameinfo->refcount++;
620     }
621 }
622 
623 static void
dbus_g_proxy_manager_unmonitor_name_owner(DBusGProxyManager * manager,const char * name)624 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager  *manager,
625 					   const char         *name)
626 {
627   DBusGProxyNameOwnerInfo *info;
628   const char *owner;
629   gboolean ret;
630 
631   ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
632   g_assert (ret);
633   g_assert (info != NULL);
634   g_assert (owner != NULL);
635 
636   info->refcount--;
637   if (info->refcount == 0)
638     {
639       GSList *names;
640       GSList *link;
641 
642       names = g_hash_table_lookup (manager->owner_names, owner);
643       link = g_slist_find_custom (names, name, find_name_in_info);
644       names = g_slist_delete_link (names, link);
645       if (names != NULL)
646 	g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
647       else
648 	g_hash_table_remove (manager->owner_names, owner);
649 
650       g_free (info->name);
651       g_free (info);
652     }
653 }
654 
655 typedef struct
656 {
657   const char *name;
658   GSList *destroyed;
659 } DBusGProxyUnassociateData;
660 
661 static void
unassociate_proxies(gpointer key,gpointer val,gpointer user_data)662 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
663 {
664   DBusGProxyList *list;
665   const char *name;
666   GSList *tmp;
667   DBusGProxyUnassociateData *data;
668 
669   list = val;
670   data = user_data;
671   name = data->name;
672 
673   for (tmp = list->proxies; tmp; tmp = tmp->next)
674     {
675       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
676       DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
677       DBusGProxyManager *manager;
678 
679       manager = priv->manager;
680 
681       if (priv->name != NULL && !strcmp (priv->name, name))
682 	{
683 	  if (!priv->for_owner)
684 	    {
685 	      /* If a service appeared and then vanished very quickly,
686 	       * it's conceivable we have an inflight request for
687 	       * GetNameOwner here.  Cancel it.
688 	       * https://bugs.freedesktop.org/show_bug.cgi?id=18573
689 	       */
690 	      if (priv->name_call)
691 		dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
692 
693 	      priv->name_call = NULL;
694 
695 	      priv->associated = FALSE;
696 	      manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
697 	    }
698 	  else
699 	    {
700 	      data->destroyed = g_slist_prepend (data->destroyed, proxy);
701               /* make contents of list into weak pointers in case the objects
702                * unref each other when disposing */
703               g_object_add_weak_pointer (G_OBJECT (proxy),
704                   &(data->destroyed->data));
705 	    }
706 	}
707     }
708 }
709 
710 static void
dbus_g_proxy_manager_replace_name_owner(DBusGProxyManager * manager,const char * name,const char * prev_owner,const char * new_owner)711 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager  *manager,
712 					 const char         *name,
713 					 const char         *prev_owner,
714 					 const char         *new_owner)
715 {
716   GSList *names;
717 
718   if (prev_owner[0] == '\0')
719     {
720       GSList *tmp;
721       GSList *removed;
722 
723       /* We have a new service, look at unassociated proxies */
724 
725       removed = NULL;
726 
727       for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
728 	{
729 	  DBusGProxy *proxy = tmp->data;
730 	  DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
731 
732 	  if (!strcmp (priv->name, name))
733 	    {
734 	      removed = g_slist_prepend (removed, tmp);
735 
736 	      dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
737 	      priv->associated = TRUE;
738 	    }
739 	}
740 
741       for (tmp = removed; tmp; tmp = tmp->next)
742 	manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
743       g_slist_free (removed);
744     }
745   else
746     {
747       DBusGProxyNameOwnerInfo *info;
748       GSList *link;
749 
750       /* Name owner changed or deleted */
751 
752       names = g_hash_table_lookup (manager->owner_names, prev_owner);
753 
754       info = NULL;
755       if (names != NULL)
756         {
757 	  link = g_slist_find_custom (names, name, find_name_in_info);
758 
759 	  if (link != NULL)
760 	    {
761 	      info = link->data;
762 
763 	      names = g_slist_delete_link (names, link);
764 
765               if (names == NULL)
766                 {
767                   g_hash_table_remove (manager->owner_names, prev_owner);
768                 }
769               else
770                 {
771                   g_hash_table_insert (manager->owner_names,
772                                        g_strdup (prev_owner), names);
773                 }
774             }
775         }
776 
777       if (new_owner[0] == '\0')
778 	{
779 	  DBusGProxyUnassociateData data;
780 	  GSList *tmp;
781 
782 	  data.name = name;
783 	  data.destroyed = NULL;
784 
785 	  /* A service went away, we need to unassociate proxies */
786 	  g_hash_table_foreach (manager->proxy_lists,
787 				unassociate_proxies, &data);
788 
789 	  UNLOCK_MANAGER (manager);
790 
791           /* the destroyed list's data pointers are weak pointers, so that we
792            * don't end up calling destroy on proxies which have already been
793            * freed up as a result of other ones being destroyed */
794 	  for (tmp = data.destroyed; tmp; tmp = tmp->next)
795             if (tmp->data != NULL)
796               {
797                 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
798                     &(tmp->data));
799                 dbus_g_proxy_destroy (tmp->data);
800               }
801 	  g_slist_free (data.destroyed);
802 
803 	  LOCK_MANAGER (manager);
804 
805 	  if (info)
806 	    {
807 	      g_free (info->name);
808 	      g_free (info);
809 	    }
810 	}
811       else if (info)
812 	{
813 	  insert_nameinfo (manager, new_owner, info);
814 	}
815     }
816 }
817 
818 static void
got_name_owner_cb(DBusGProxy * bus_proxy,DBusGProxyCall * call,void * user_data)819 got_name_owner_cb (DBusGProxy       *bus_proxy,
820 		   DBusGProxyCall   *call,
821 		   void             *user_data)
822 {
823   DBusGProxy *proxy = user_data;
824   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
825   GError *error;
826   char *owner;
827 
828   error = NULL;
829   owner = NULL;
830 
831   LOCK_MANAGER (priv->manager);
832 
833   if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
834 			      G_TYPE_STRING, &owner,
835 			      G_TYPE_INVALID))
836     {
837       if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
838 	{
839 	  priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
840 	}
841       else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
842 	g_warning ("Couldn't get name owner (%s): %s",
843 		   dbus_g_error_get_name (error),
844 		   error->message);
845       else
846 	g_warning ("Couldn't get name owner (code %d): %s",
847                    error->code, error->message);
848       g_clear_error (&error);
849       goto out;
850     }
851   else
852     {
853       dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
854       priv->associated = TRUE;
855     }
856 
857  out:
858   priv->name_call = NULL;
859   UNLOCK_MANAGER (priv->manager);
860   g_free (owner);
861 }
862 
863 static char *
get_name_owner(DBusConnection * connection,const char * name,GError ** error)864 get_name_owner (DBusConnection     *connection,
865 		const char         *name,
866 		GError            **error)
867 {
868   DBusError derror;
869   DBusMessage *request, *reply;
870   char *base_name;
871 
872   dbus_error_init (&derror);
873 
874   base_name = NULL;
875   reply = NULL;
876 
877   request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
878 					  DBUS_PATH_DBUS,
879 					  DBUS_INTERFACE_DBUS,
880 					  "GetNameOwner");
881   if (request == NULL)
882     g_error ("Out of memory");
883 
884   if (!dbus_message_append_args (request,
885 				 DBUS_TYPE_STRING, &name,
886 				 DBUS_TYPE_INVALID))
887     g_error ("Out of memory");
888 
889   reply =
890     dbus_connection_send_with_reply_and_block (connection,
891                                                request,
892                                                2000, &derror);
893   if (reply == NULL)
894     goto error;
895 
896   if (dbus_set_error_from_message (&derror, reply))
897     goto error;
898 
899   if (!dbus_message_get_args (reply, &derror,
900 			      DBUS_TYPE_STRING, &base_name,
901 			      DBUS_TYPE_INVALID))
902     goto error;
903 
904   base_name = g_strdup (base_name);
905   goto out;
906 
907  error:
908   g_assert (dbus_error_is_set (&derror));
909   dbus_set_g_error (error, &derror);
910   dbus_error_free (&derror);
911 
912  out:
913   if (request)
914     dbus_message_unref (request);
915   if (reply)
916     dbus_message_unref (reply);
917 
918   return base_name;
919 }
920 
921 
922 static void
guint_slice_free(gpointer data)923 guint_slice_free (gpointer data)
924 {
925   g_slice_free (guint, data);
926 }
927 
928 
929 static void
dbus_g_proxy_manager_register(DBusGProxyManager * manager,DBusGProxy * proxy)930 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
931                                DBusGProxy        *proxy)
932 {
933   DBusGProxyList *list;
934   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
935 
936   LOCK_MANAGER (manager);
937 
938   if (manager->proxy_lists == NULL)
939     {
940       g_assert (manager->owner_names == NULL);
941       g_assert (manager->owner_match_rules == NULL);
942 
943       list = NULL;
944       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
945                                                     tristring_equal,
946                                                     NULL,
947                                                     (GFreeFunc) g_proxy_list_free);
948       manager->owner_names = g_hash_table_new_full (g_str_hash,
949                                                     g_str_equal,
950                                                     g_free,
951                                                     NULL);
952       manager->owner_match_rules = g_hash_table_new_full (g_str_hash,
953                                                           g_str_equal,
954                                                           g_free,
955                                                           guint_slice_free);
956     }
957   else
958     {
959       char *tri;
960 
961       tri = tristring_from_proxy (proxy);
962 
963       list = g_hash_table_lookup (manager->proxy_lists, tri);
964 
965       g_free (tri);
966     }
967 
968   if (list == NULL)
969     {
970       list = g_proxy_list_new (proxy);
971 
972       g_hash_table_replace (manager->proxy_lists,
973                             list->name, list);
974     }
975 
976   if (list->proxies == NULL && priv->name)
977     {
978       /* We have to add match rules to the server,
979        * but only if the server is a message bus,
980        * not if it's a peer.
981        */
982       char *rule;
983       guint *refcount;
984 
985       rule = g_proxy_get_signal_match_rule (proxy);
986       /* We don't check for errors; it's not like anyone would handle them, and
987        * we don't want a round trip here.
988        */
989       dbus_bus_add_match (manager->connection, rule, NULL);
990       g_free (rule);
991 
992       refcount = g_hash_table_lookup (manager->owner_match_rules, priv->name);
993 
994       if (refcount != NULL)
995         {
996           g_assert (*refcount != 0);
997           g_assert (*refcount < G_MAXUINT);
998           (*refcount)++;
999         }
1000       else
1001         {
1002           char *rule;
1003           rule = get_owner_match_rule (priv->name);
1004           dbus_bus_add_match (manager->connection,
1005                               rule, NULL);
1006           g_free (rule);
1007 
1008           refcount = g_slice_new (guint);
1009           *refcount = 1;
1010           g_hash_table_insert (manager->owner_match_rules,
1011                                g_strdup (priv->name), refcount);
1012         }
1013     }
1014 
1015   g_assert (g_slist_find (list->proxies, proxy) == NULL);
1016 
1017   list->proxies = g_slist_prepend (list->proxies, proxy);
1018 
1019   if (!priv->for_owner)
1020     {
1021       const char *owner;
1022       DBusGProxyNameOwnerInfo *info;
1023 
1024       if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
1025 	{
1026 	  priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
1027 						     got_name_owner_cb,
1028 						     proxy, NULL,
1029 						     G_TYPE_STRING,
1030 						     priv->name,
1031 						     G_TYPE_INVALID);
1032 
1033 	  priv->associated = FALSE;
1034 	}
1035       else
1036 	{
1037 	  info->refcount++;
1038 	  priv->associated = TRUE;
1039 	}
1040     }
1041 
1042   UNLOCK_MANAGER (manager);
1043 }
1044 
1045 static void
dbus_g_proxy_manager_unregister(DBusGProxyManager * manager,DBusGProxy * proxy)1046 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
1047                                 DBusGProxy        *proxy)
1048 {
1049   DBusGProxyList *list;
1050   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1051   char *tri;
1052 
1053   LOCK_MANAGER (manager);
1054 
1055 #ifndef G_DISABLE_CHECKS
1056   if (manager->proxy_lists == NULL)
1057     {
1058       g_warning ("Trying to unregister a proxy but there aren't any registered");
1059       return;
1060     }
1061 #endif
1062 
1063   tri = tristring_from_proxy (proxy);
1064 
1065   list = g_hash_table_lookup (manager->proxy_lists, tri);
1066 
1067 #ifndef G_DISABLE_CHECKS
1068   if (list == NULL)
1069     {
1070       g_warning ("Trying to unregister a proxy but it isn't registered");
1071       return;
1072     }
1073 #endif
1074 
1075   g_assert (g_slist_find (list->proxies, proxy) != NULL);
1076 
1077   list->proxies = g_slist_remove (list->proxies, proxy);
1078 
1079   g_assert (g_slist_find (list->proxies, proxy) == NULL);
1080 
1081   if (!priv->for_owner)
1082     {
1083       if (!priv->associated)
1084 	{
1085 	  GSList *link;
1086 
1087 	  if (priv->name_call != 0)
1088 	    {
1089 	      dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
1090 	      priv->name_call = 0;
1091 	    }
1092 	  else
1093 	    {
1094               link = g_slist_find (manager->unassociated_proxies, proxy);
1095               if (link != NULL)
1096                 {
1097                   manager->unassociated_proxies = g_slist_delete_link (
1098                       manager->unassociated_proxies, link);
1099                 }
1100 	    }
1101 	}
1102       else
1103 	{
1104 	  g_assert (priv->name_call == 0);
1105 
1106 	  dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
1107 	}
1108     }
1109 
1110   if (list->proxies == NULL)
1111     {
1112       char *rule;
1113       g_hash_table_remove (manager->proxy_lists,
1114                            tri);
1115 
1116       rule = g_proxy_get_signal_match_rule (proxy);
1117       dbus_bus_remove_match (manager->connection,
1118                              rule, NULL);
1119       g_free (rule);
1120 
1121       if (priv->name)
1122         {
1123           guint *refcount;
1124           refcount = g_hash_table_lookup (manager->owner_match_rules, priv->name);
1125           (*refcount)--;
1126 
1127           if (*refcount == 0)
1128             {
1129               rule = get_owner_match_rule (priv->name);
1130               dbus_bus_remove_match (manager->connection,
1131                                      rule, NULL);
1132               g_free (rule);
1133               g_hash_table_remove (manager->owner_match_rules, priv->name);
1134             }
1135         }
1136     }
1137 
1138   if (g_hash_table_size (manager->proxy_lists) == 0)
1139     {
1140       g_hash_table_destroy (manager->proxy_lists);
1141       manager->proxy_lists = NULL;
1142     }
1143 
1144   if (manager->owner_match_rules != NULL &&
1145       g_hash_table_size (manager->owner_match_rules) == 0)
1146     {
1147       g_hash_table_destroy (manager->owner_match_rules);
1148       manager->owner_match_rules = NULL;
1149     }
1150 
1151   g_free (tri);
1152 
1153   UNLOCK_MANAGER (manager);
1154 }
1155 
1156 static void
list_proxies_foreach(gpointer key,gpointer value,gpointer user_data)1157 list_proxies_foreach (gpointer key,
1158                       gpointer value,
1159                       gpointer user_data)
1160 {
1161   DBusGProxyList *list;
1162   GSList **ret;
1163   GSList *tmp;
1164 
1165   list = value;
1166   ret = user_data;
1167 
1168   tmp = list->proxies;
1169   while (tmp != NULL)
1170     {
1171       DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
1172 
1173       g_object_ref (proxy);
1174       *ret = g_slist_prepend (*ret, proxy);
1175 
1176       tmp = tmp->next;
1177     }
1178 }
1179 
1180 static GSList*
dbus_g_proxy_manager_list_all(DBusGProxyManager * manager)1181 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
1182 {
1183   GSList *ret;
1184 
1185   ret = NULL;
1186 
1187   if (manager->proxy_lists)
1188     {
1189       g_hash_table_foreach (manager->proxy_lists,
1190                             list_proxies_foreach,
1191                             &ret);
1192     }
1193 
1194   return ret;
1195 }
1196 
1197 static DBusHandlerResult
dbus_g_proxy_manager_filter(DBusConnection * connection,DBusMessage * message,void * user_data)1198 dbus_g_proxy_manager_filter (DBusConnection    *connection,
1199                              DBusMessage       *message,
1200                              void              *user_data)
1201 {
1202   DBusGProxyManager *manager;
1203 
1204   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
1205     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1206 
1207   manager = user_data;
1208 
1209   dbus_g_proxy_manager_ref (manager);
1210 
1211   LOCK_MANAGER (manager);
1212 
1213   if (dbus_message_is_signal (message,
1214                               DBUS_INTERFACE_LOCAL,
1215                               "Disconnected"))
1216     {
1217       /* Destroy all the proxies, quite possibly resulting in unreferencing
1218        * the proxy manager and the connection as well.
1219        */
1220       GSList *all;
1221       GSList *tmp;
1222 
1223       all = dbus_g_proxy_manager_list_all (manager);
1224 
1225       tmp = all;
1226       while (tmp != NULL)
1227         {
1228           DBusGProxy *proxy;
1229 
1230           proxy = DBUS_G_PROXY (tmp->data);
1231 
1232           UNLOCK_MANAGER (manager);
1233           dbus_g_proxy_destroy (proxy);
1234           g_object_unref (G_OBJECT (proxy));
1235           LOCK_MANAGER (manager);
1236 
1237           tmp = tmp->next;
1238         }
1239 
1240       g_slist_free (all);
1241 
1242 #ifndef G_DISABLE_CHECKS
1243       if (manager->proxy_lists != NULL)
1244         g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
1245 #endif
1246     }
1247   else
1248     {
1249       char *tri;
1250       GSList *full_list;
1251       GSList *owned_names;
1252       GSList *tmp;
1253       const char *sender;
1254 
1255       sender = dbus_message_get_sender (message);
1256 
1257       /* First we handle NameOwnerChanged internally */
1258       if (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0 &&
1259 	  dbus_message_is_signal (message,
1260 				  DBUS_INTERFACE_DBUS,
1261 				  "NameOwnerChanged"))
1262 	{
1263 	  const char *name;
1264 	  const char *prev_owner;
1265 	  const char *new_owner;
1266 	  DBusError derr;
1267 
1268 	  dbus_error_init (&derr);
1269 	  if (!dbus_message_get_args (message,
1270 				      &derr,
1271 				      DBUS_TYPE_STRING,
1272 				      &name,
1273 				      DBUS_TYPE_STRING,
1274 				      &prev_owner,
1275 				      DBUS_TYPE_STRING,
1276 				      &new_owner,
1277 				      DBUS_TYPE_INVALID))
1278 	    {
1279 	      /* Ignore this error */
1280 	      dbus_error_free (&derr);
1281 	    }
1282 	  else if (manager->owner_names != NULL)
1283 	    {
1284 	      dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
1285 	    }
1286 	}
1287 
1288       /* dbus spec requires these, libdbus validates */
1289       g_assert (dbus_message_get_path (message) != NULL);
1290       g_assert (dbus_message_get_interface (message) != NULL);
1291       g_assert (dbus_message_get_member (message) != NULL);
1292 
1293       tri = tristring_from_message (message);
1294 
1295       if (manager->proxy_lists)
1296 	{
1297 	  DBusGProxyList *owner_list;
1298 	  owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
1299 	  if (owner_list)
1300 	    full_list = g_slist_copy (owner_list->proxies);
1301 	  else
1302 	    full_list = NULL;
1303 	}
1304       else
1305 	full_list = NULL;
1306 
1307       g_free (tri);
1308 
1309       if (manager->owner_names && sender)
1310 	{
1311 	  owned_names = g_hash_table_lookup (manager->owner_names, sender);
1312 	  for (tmp = owned_names; tmp; tmp = tmp->next)
1313 	    {
1314 	      DBusGProxyList *owner_list;
1315 	      DBusGProxyNameOwnerInfo *nameinfo;
1316 
1317 	      nameinfo = tmp->data;
1318 	      g_assert (nameinfo->refcount > 0);
1319 	      tri = tristring_alloc_from_strings (0, nameinfo->name,
1320 						  dbus_message_get_path (message),
1321 						  dbus_message_get_interface (message));
1322 
1323 	      owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
1324 	      if (owner_list != NULL)
1325                 {
1326 	          GSList *elt;
1327 
1328 	          /* Ignore duplicates when adding to full_list */
1329 	          for (elt = owner_list->proxies; elt; elt = g_slist_next (elt))
1330                     {
1331 	              if (!g_slist_find (full_list, elt->data))
1332 	                full_list = g_slist_append (full_list, elt->data);
1333 	            }
1334 	        }
1335 	      g_free (tri);
1336 	    }
1337 	}
1338 
1339 #if 0
1340       g_print ("proxy got %s,%s,%s = list %p\n",
1341                tri,
1342                tri + strlen (tri) + 1,
1343                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
1344                list);
1345 #endif
1346 
1347       /* Emit the signal */
1348 
1349       g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
1350 
1351       for (tmp = full_list; tmp; tmp = tmp->next)
1352 	{
1353 	  DBusGProxy *proxy;
1354 
1355 	  proxy = DBUS_G_PROXY (tmp->data);
1356 
1357 	  UNLOCK_MANAGER (manager);
1358 	  dbus_g_proxy_emit_remote_signal (proxy, message);
1359 	  g_object_unref (G_OBJECT (proxy));
1360 	  LOCK_MANAGER (manager);
1361 	}
1362       g_slist_free (full_list);
1363     }
1364 
1365   UNLOCK_MANAGER (manager);
1366   dbus_g_proxy_manager_unref (manager);
1367 
1368   /* "Handling" signals doesn't make sense, they are for everyone
1369    * who cares
1370    */
1371   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1372 }
1373 
1374 
1375 
1376 /*      ---------- DBusGProxy --------------   */
1377 #define DBUS_G_PROXY_DESTROYED(proxy)  (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
1378 
1379 static void
1380 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
1381                                       GValue       *return_value,
1382                                       guint         n_param_values,
1383                                       const GValue *param_values,
1384                                       gpointer      invocation_hint,
1385                                       gpointer      marshal_data);
1386 enum
1387 {
1388   PROP_0,
1389   PROP_NAME,
1390   PROP_PATH,
1391   PROP_INTERFACE,
1392   PROP_CONNECTION
1393 };
1394 
1395 enum
1396 {
1397   DESTROY,
1398   RECEIVED,
1399   LAST_SIGNAL
1400 };
1401 
1402 static void *parent_class;
1403 static guint signals[LAST_SIGNAL] = { 0 };
1404 
1405 static void
dbus_g_proxy_init(DBusGProxy * proxy)1406 dbus_g_proxy_init (DBusGProxy *proxy)
1407 {
1408   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1409 
1410   g_datalist_init (&priv->signal_signatures);
1411   priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
1412 				(GDestroyNotify) dbus_pending_call_unref);
1413   priv->name_call = 0;
1414   priv->associated = FALSE;
1415   priv->default_timeout = -1;
1416 }
1417 
1418 static GObject *
dbus_g_proxy_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)1419 dbus_g_proxy_constructor (GType                  type,
1420 			  guint                  n_construct_properties,
1421 			  GObjectConstructParam *construct_properties)
1422 {
1423   DBusGProxy *proxy;
1424   DBusGProxyClass *klass;
1425   GObjectClass *parent_class;
1426   DBusGProxyPrivate *priv;
1427 
1428   klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
1429 
1430   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
1431 
1432   proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
1433 						    construct_properties));
1434 
1435   priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
1436 
1437   /* if these assertions fail, a deriving class has not set our required
1438    * parameters - our own public constructors do return_if_fail checks
1439    * on these parameters being provided. unfortunately we can't assert
1440    * for manager because it's allowed to be NULL when tha mangager is
1441    * setting up a bus proxy for its own calls */
1442   g_assert (priv->path != NULL);
1443   g_assert (priv->interface != NULL);
1444 
1445   if (priv->manager != NULL)
1446     {
1447       dbus_g_proxy_manager_register (priv->manager, proxy);
1448     }
1449 
1450   return G_OBJECT (proxy);
1451 }
1452 
1453 static void
dbus_g_proxy_class_init(DBusGProxyClass * klass)1454 dbus_g_proxy_class_init (DBusGProxyClass *klass)
1455 {
1456   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1457 
1458   parent_class = g_type_class_peek_parent (klass);
1459 
1460   g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
1461 
1462   object_class->set_property = dbus_g_proxy_set_property;
1463   object_class->get_property = dbus_g_proxy_get_property;
1464 
1465   g_object_class_install_property (object_class,
1466 				   PROP_NAME,
1467 				   g_param_spec_string ("name",
1468 							"name",
1469 							"name",
1470 							NULL,
1471 							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1472 
1473   g_object_class_install_property (object_class,
1474 				   PROP_PATH,
1475 				   g_param_spec_string ("path",
1476 							"path",
1477 							"path",
1478 							NULL,
1479 							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1480 
1481   g_object_class_install_property (object_class,
1482 				   PROP_INTERFACE,
1483 				   g_param_spec_string ("interface",
1484 							"interface",
1485 							"interface",
1486 							NULL,
1487 							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1488 
1489   g_object_class_install_property (object_class,
1490 				   PROP_CONNECTION,
1491 				   g_param_spec_boxed ("connection",
1492 							"connection",
1493 							"connection",
1494 							DBUS_TYPE_G_CONNECTION,
1495 							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1496 
1497   object_class->finalize = dbus_g_proxy_finalize;
1498   object_class->dispose = dbus_g_proxy_dispose;
1499   object_class->constructor = dbus_g_proxy_constructor;
1500 
1501 /**
1502  * DBusGProxy::destroy:
1503  * @dbusgproxy: the object which received the signal.
1504  *
1505  * Deprecated: New code should use #GDBusProxy instead.
1506  */
1507   signals[DESTROY] =
1508     g_signal_new ("destroy",
1509 		  G_OBJECT_CLASS_TYPE (object_class),
1510                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
1511                   0,
1512 		  NULL, NULL,
1513                   g_cclosure_marshal_VOID__VOID,
1514 		  G_TYPE_NONE, 0);
1515 
1516 /*
1517  * DBusGProxy::received:
1518  * @dbusgproxy: the object which received the signal.
1519  *
1520  * Deprecated: New code should use #GDBusProxy instead.
1521  */
1522   signals[RECEIVED] =
1523     g_signal_new ("received",
1524 		  G_OBJECT_CLASS_TYPE (object_class),
1525                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
1526                   0,
1527                   NULL, NULL,
1528                   marshal_dbus_message_to_g_marshaller,
1529                   G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
1530 }
1531 
1532 static gboolean
cancel_pending_call(gpointer key,gpointer val,gpointer data)1533 cancel_pending_call (gpointer key, gpointer val, gpointer data)
1534 {
1535   DBusPendingCall *pending = val;
1536 
1537   dbus_pending_call_cancel (pending);
1538 
1539   return TRUE;
1540 }
1541 
1542 static void
dbus_g_proxy_dispose(GObject * object)1543 dbus_g_proxy_dispose (GObject *object)
1544 {
1545   DBusGProxy *proxy = DBUS_G_PROXY (object);
1546   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1547 
1548   if (priv->pending_calls == NULL)
1549     {
1550       return;
1551     }
1552 
1553   /* Cancel outgoing pending calls */
1554   g_hash_table_foreach_remove (priv->pending_calls, cancel_pending_call, NULL);
1555   g_hash_table_destroy (priv->pending_calls);
1556   priv->pending_calls = NULL;
1557 
1558   if (priv->manager && proxy != priv->manager->bus_proxy)
1559     {
1560       dbus_g_proxy_manager_unregister (priv->manager, proxy);
1561       dbus_g_proxy_manager_unref (priv->manager);
1562     }
1563   priv->manager = NULL;
1564 
1565   g_datalist_clear (&priv->signal_signatures);
1566 
1567   g_signal_emit (object, signals[DESTROY], 0);
1568 
1569   G_OBJECT_CLASS (parent_class)->dispose (object);
1570 }
1571 
1572 static void
dbus_g_proxy_finalize(GObject * object)1573 dbus_g_proxy_finalize (GObject *object)
1574 {
1575   DBusGProxy *proxy = DBUS_G_PROXY (object);
1576   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1577 
1578   g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
1579 
1580   g_free (priv->name);
1581   g_free (priv->path);
1582   g_free (priv->interface);
1583 
1584   G_OBJECT_CLASS (parent_class)->finalize (object);
1585 }
1586 
1587 static void
dbus_g_proxy_destroy(DBusGProxy * proxy)1588 dbus_g_proxy_destroy (DBusGProxy *proxy)
1589 {
1590   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
1591    * from GtkObject?
1592    */
1593   g_object_run_dispose (G_OBJECT (proxy));
1594 }
1595 
1596 static void
dbus_g_proxy_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1597 dbus_g_proxy_set_property (GObject *object,
1598 			   guint prop_id,
1599 			   const GValue *value,
1600 			   GParamSpec *pspec)
1601 {
1602   DBusGProxy *proxy = DBUS_G_PROXY (object);
1603   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1604   DBusGConnection *connection;
1605 
1606   switch (prop_id)
1607     {
1608     case PROP_NAME:
1609       priv->name = g_strdup (g_value_get_string (value));
1610       if (priv->name)
1611         priv->for_owner = (priv->name[0] == ':');
1612       else
1613         priv->for_owner = TRUE;
1614       break;
1615     case PROP_PATH:
1616       priv->path = g_strdup (g_value_get_string (value));
1617       break;
1618     case PROP_INTERFACE:
1619       priv->interface = g_strdup (g_value_get_string (value));
1620       break;
1621     case PROP_CONNECTION:
1622       connection = g_value_get_boxed (value);
1623       if (connection != NULL)
1624         {
1625           priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
1626         }
1627       break;
1628     default:
1629       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1630       break;
1631     }
1632 }
1633 
1634 static void
dbus_g_proxy_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1635 dbus_g_proxy_get_property (GObject *object,
1636 			   guint prop_id,
1637 			   GValue *value,
1638 			   GParamSpec *pspec)
1639 {
1640   DBusGProxy *proxy = DBUS_G_PROXY (object);
1641   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1642 
1643   switch (prop_id)
1644     {
1645     case PROP_NAME:
1646       g_value_set_string (value, priv->name);
1647       break;
1648     case PROP_PATH:
1649       g_value_set_string (value, priv->path);
1650       break;
1651     case PROP_INTERFACE:
1652       g_value_set_string (value, priv->interface);
1653       break;
1654     case PROP_CONNECTION:
1655       g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
1656       break;
1657     default:
1658       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1659       break;
1660     }
1661 }
1662 
1663 /* this is to avoid people using g_signal_connect() directly,
1664  * to avoid confusion with local signal names, and because
1665  * of the horribly broken current setup (signals are added
1666  * globally to all proxies)
1667  */
1668 static char*
create_signal_name(const char * interface,const char * signal)1669 create_signal_name (const char *interface,
1670                     const char *signal)
1671 {
1672   GString *str;
1673   char *p;
1674 
1675   str = g_string_new (interface);
1676 
1677   g_string_append (str, "-");
1678 
1679   g_string_append (str, signal);
1680 
1681   /* GLib will silently barf on '.' in signal names */
1682   p = str->str;
1683   while (*p)
1684     {
1685       if (*p == '.')
1686         *p = '-';
1687       ++p;
1688     }
1689 
1690   return g_string_free (str, FALSE);
1691 }
1692 
1693 static void
marshal_dbus_message_to_g_marshaller(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)1694 marshal_dbus_message_to_g_marshaller (GClosure     *closure,
1695                                       GValue       *return_value,
1696                                       guint         n_param_values,
1697                                       const GValue *param_values,
1698                                       gpointer      invocation_hint,
1699                                       gpointer      marshal_data)
1700 {
1701   /* Incoming here we have three params, the instance (Proxy), the
1702    * DBusMessage, the signature. We want to convert that to an
1703    * expanded GValue array, then call an appropriate normal GLib
1704    * marshaller.
1705    */
1706 #define MAX_SIGNATURE_ARGS 20
1707   GValueArray *value_array;
1708   DBusGProxy *proxy;
1709   DBusMessage *message;
1710   GArray *gsignature;
1711   const GType *types;
1712   DBusGProxyPrivate *priv;
1713 
1714   g_assert (n_param_values == 3);
1715 
1716   proxy = g_value_get_object (&param_values[0]);
1717   message = g_value_get_boxed (&param_values[1]);
1718   gsignature = g_value_get_pointer (&param_values[2]);
1719 
1720   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
1721   g_return_if_fail (message != NULL);
1722   g_return_if_fail (gsignature != NULL);
1723 
1724   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1725 
1726   {
1727     DBusGValueMarshalCtx context;
1728     context.recursion_depth = 0;
1729     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
1730     context.proxy = proxy;
1731 
1732     types = (const GType*) gsignature->data;
1733     value_array = _dbus_gvalue_demarshal_message (&context, message,
1734 						 gsignature->len, types, NULL);
1735   }
1736 
1737   if (value_array == NULL)
1738     return;
1739 
1740   g_value_array_prepend (value_array, NULL);
1741   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
1742   g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
1743 
1744   g_cclosure_marshal_generic (closure, return_value, value_array->n_values,
1745       value_array->values, invocation_hint, marshal_data);
1746 
1747   g_value_array_free (value_array);
1748 }
1749 
1750 static void
dbus_g_proxy_emit_remote_signal(DBusGProxy * proxy,DBusMessage * message)1751 dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
1752                                  DBusMessage *message)
1753 {
1754   const char *interface;
1755   const char *signal;
1756   char *name;
1757   GQuark q;
1758   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1759   GArray *msg_gsignature = NULL;
1760 
1761   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
1762 
1763   interface = dbus_message_get_interface (message);
1764   signal = dbus_message_get_member (message);
1765 
1766   g_assert (interface != NULL);
1767   g_assert (signal != NULL);
1768 
1769   name = create_signal_name (interface, signal);
1770 
1771   /* If the quark isn't preexisting, there's no way there
1772    * are any handlers connected. We don't want to create
1773    * extra quarks for every possible signal.
1774    */
1775   q = g_quark_try_string (name);
1776 
1777   if (q != 0)
1778     {
1779       GArray *gsignature;
1780       guint i;
1781 
1782       gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
1783       if (gsignature == NULL)
1784 	goto out;
1785 
1786       msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
1787 						       TRUE);
1788       for (i = 0; i < gsignature->len; i++)
1789 	{
1790 	  if (msg_gsignature->len == i
1791 	      || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
1792 	    goto mismatch;
1793 	}
1794       if (msg_gsignature->len != i)
1795 	goto mismatch;
1796 
1797       g_signal_emit (proxy,
1798 		     signals[RECEIVED],
1799 		     q,
1800 		     message,
1801 		     msg_gsignature);
1802     }
1803 
1804  out:
1805   g_free (name);
1806   if (msg_gsignature)
1807     g_array_free (msg_gsignature, TRUE);
1808   return;
1809  mismatch:
1810 #if 0
1811   /* Don't spew on remote errors */
1812   g_warning ("Unexpected message signature '%s' for signal '%s'\n",
1813 	     dbus_message_get_signature (message),
1814 	     name);
1815 #endif
1816   goto out;
1817 }
1818 
1819 /**
1820  * DBusGProxyCallNotify:
1821  * @proxy: the proxy on which the method was called
1822  * @call_id: the call in progress
1823  * @user_data: data passed to dbus_g_proxy_begin_call() or similar
1824  *
1825  * Called when a reply to the call represented by @call_id arrives.
1826  * Use dbus_g_proxy_end_call() to see whether @call_id succeeded or
1827  * failed, and get the arguments returned (if any) on success.
1828  *
1829  * Deprecated: New code should use GDBus instead. The closest equivalent
1830  *  is the standard #GAsyncReadyCallback mechanism.
1831  */
1832 
1833 typedef struct
1834 {
1835   DBusGProxy *proxy;
1836   guint call_id;
1837   DBusGProxyCallNotify func;
1838   void *data;
1839   GDestroyNotify free_data_func;
1840 } GPendingNotifyClosure;
1841 
1842 static void
d_pending_call_notify(DBusPendingCall * dcall,void * data)1843 d_pending_call_notify (DBusPendingCall *dcall,
1844                        void            *data)
1845 {
1846   GPendingNotifyClosure *closure = data;
1847 
1848   (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
1849 }
1850 
1851 static void
d_pending_call_free(void * data)1852 d_pending_call_free (void *data)
1853 {
1854   GPendingNotifyClosure *closure = data;
1855 
1856   if (closure->free_data_func)
1857     (* closure->free_data_func) (closure->data);
1858 
1859   g_free (closure);
1860 }
1861 
1862 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
1863 G_STMT_START { \
1864   GType valtype; \
1865   guint i = 0; \
1866   \
1867   VALARRAY = g_value_array_new (6); \
1868   valtype = FIRST_ARG_TYPE; \
1869   \
1870   while (valtype != G_TYPE_INVALID) \
1871     { \
1872       gchar *collect_err; \
1873       GValue *val; \
1874       \
1875       g_value_array_append (VALARRAY, NULL); \
1876       val = g_value_array_get_nth (VALARRAY, i); \
1877       g_value_init (val, valtype); \
1878       collect_err = NULL; \
1879       G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
1880       \
1881       if (collect_err) \
1882         { \
1883           g_critical ("%s: unable to collect argument %u: %s", \
1884               G_STRFUNC, i, collect_err); \
1885           g_free (collect_err); \
1886           g_value_array_free (VALARRAY); \
1887           VALARRAY = NULL; \
1888           break; \
1889         } \
1890       \
1891       valtype = va_arg (ARGS, GType); \
1892       i++; \
1893     } \
1894 } G_STMT_END
1895 
1896 DBusGProxyCall *
manager_begin_bus_call(DBusGProxyManager * manager,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,GType first_arg_type,...)1897 manager_begin_bus_call (DBusGProxyManager    *manager,
1898 			const char           *method,
1899 			DBusGProxyCallNotify  notify,
1900 			gpointer              user_data,
1901 			GDestroyNotify        destroy,
1902 			GType                 first_arg_type,
1903 			...)
1904 {
1905   guint call_id = 0;
1906   DBusGProxyPrivate *priv;
1907   va_list args;
1908   GValueArray *arg_values;
1909 
1910   va_start (args, first_arg_type);
1911 
1912   if (!manager->bus_proxy)
1913     {
1914       manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
1915 					 "name", DBUS_SERVICE_DBUS,
1916 					 "path", DBUS_PATH_DBUS,
1917 					 "interface", DBUS_INTERFACE_DBUS,
1918 					 NULL);
1919       priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
1920       priv->manager = manager;
1921     }
1922 
1923   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
1924 
1925   if (arg_values != NULL)
1926     {
1927       call_id = dbus_g_proxy_begin_call_internal (manager->bus_proxy, method,
1928           notify, user_data, destroy, arg_values, -1);
1929 
1930       g_value_array_free (arg_values);
1931     }
1932 
1933   va_end (args);
1934 
1935   return DBUS_G_PROXY_ID_TO_CALL (call_id);
1936 }
1937 
1938 /**
1939  * SECTION:dbus-gproxy
1940  * @title: DBusGProxy
1941  * @short_description: DBus Proxy
1942  * @see_also: #DBusGProxy
1943  * @stability: Stable
1944  *
1945  * A #DBusGProxy is a #GObject representing a remote object in a D-Bus
1946  * service.
1947  *
1948  * Deprecated: New code should use #GDBusProxy instead.
1949  */
1950 
1951 /**
1952  * DBusGProxy:
1953  *
1954  * A #GObject representing a remote object in a D-Bus service.
1955  *
1956  * Deprecated: New code should use GDBus instead. The closest equivalent
1957  *  is #GDBusProxy.
1958  */
1959 
1960 /**
1961  * DBusGProxyCall:
1962  *
1963  * An opaque pointer representing an asynchronous call in progress.
1964  *
1965  * Deprecated: New code should use GDBus instead. There is no direct
1966  *  equivalent in GDBus, but the standard #GCancellable mechanism is
1967  *  analogous.
1968  */
1969 
1970 /*
1971  * dbus_g_proxy_get_type:
1972  * Standard GObject get_type() function for DBusGProxy.
1973  *
1974  * Returns: type ID for DBusGProxy class
1975  *
1976  * Deprecated: New code should use #GDBusProxy instead.
1977  */
1978 GType
dbus_g_proxy_get_type(void)1979 dbus_g_proxy_get_type (void)
1980 {
1981   static GType object_type = 0;
1982 
1983   if (!object_type)
1984     {
1985       static const GTypeInfo object_info =
1986         {
1987           sizeof (DBusGProxyClass),
1988           (GBaseInitFunc) NULL,
1989           (GBaseFinalizeFunc) NULL,
1990           (GClassInitFunc) dbus_g_proxy_class_init,
1991           NULL,           /* class_finalize */
1992           NULL,           /* class_data */
1993           sizeof (DBusGProxy),
1994           0,              /* n_preallocs */
1995           (GInstanceInitFunc) dbus_g_proxy_init,
1996         };
1997 
1998       object_type = g_type_register_static (G_TYPE_OBJECT,
1999                                             "DBusGProxy",
2000                                             &object_info, 0);
2001     }
2002 
2003   return object_type;
2004 }
2005 
2006 static DBusGProxy*
dbus_g_proxy_new(DBusGConnection * connection,const char * name,const char * path_name,const char * interface_name)2007 dbus_g_proxy_new (DBusGConnection *connection,
2008                   const char      *name,
2009                   const char      *path_name,
2010                   const char      *interface_name)
2011 {
2012   DBusGProxy *proxy;
2013 
2014   g_assert (connection != NULL);
2015 
2016   proxy = g_object_new (DBUS_TYPE_G_PROXY,
2017                         "name", name,
2018                         "path", path_name,
2019                         "interface", interface_name,
2020                         "connection", connection, NULL);
2021 
2022   return proxy;
2023 }
2024 
2025 /**
2026  * dbus_g_proxy_new_for_name:
2027  * @connection: the connection to the remote bus
2028  * @name: any name on the message bus
2029  * @path: name of the object instance to call methods on
2030  * @iface: name of the interface to call methods on
2031  *
2032  * Creates a new proxy for a remote interface exported by a connection
2033  * on a message bus. Method calls and signal connections over this
2034  * proxy will go to the name owner; the name's owner is expected to
2035  * support the given interface name. THE NAME OWNER MAY CHANGE OVER
2036  * TIME, for example between two different method calls, unless the
2037  * name is a unique name. If you need a fixed owner, you need to
2038  * request the current owner and bind a proxy to its unique name
2039  * rather than to the generic name; see
2040  * dbus_g_proxy_new_for_name_owner().
2041  *
2042  * A name-associated proxy only makes sense with a message bus, not
2043  * for app-to-app direct dbus connections.
2044  *
2045  * This proxy will only emit the "destroy" signal if the
2046  * #DBusConnection is disconnected, the proxy has no remaining
2047  * references, or the name is a unique name and its owner
2048  * disappears. If a well-known name changes owner, the proxy will
2049  * still be alive.
2050  *
2051  * Returns: new proxy object
2052  *
2053  * Deprecated: New code should use GDBus instead. The closest equivalent
2054  *  is g_dbus_proxy_new_sync().
2055  */
2056 DBusGProxy*
dbus_g_proxy_new_for_name(DBusGConnection * connection,const char * name,const char * path,const char * iface)2057 dbus_g_proxy_new_for_name (DBusGConnection *connection,
2058                            const char      *name,
2059                            const char      *path,
2060                            const char      *iface)
2061 {
2062   g_return_val_if_fail (connection != NULL, NULL);
2063   g_return_val_if_fail (g_dbus_is_name (name), NULL);
2064   g_return_val_if_fail (g_variant_is_object_path (path), NULL);
2065   g_return_val_if_fail (g_dbus_is_interface_name (iface), NULL);
2066 
2067   return dbus_g_proxy_new (connection, name, path, iface);
2068 }
2069 
2070 /**
2071  * dbus_g_proxy_new_for_name_owner:
2072  * @connection: the connection to the remote bus
2073  * @name: any name on the message bus
2074  * @path: name of the object inside the service to call methods on
2075  * @iface: name of the interface to call methods on
2076  * @error: return location for an error
2077  *
2078  * Similar to dbus_g_proxy_new_for_name(), but makes a round-trip
2079  * request to the message bus to get the current name owner, then
2080  * binds the proxy to the unique name of the current owner, rather
2081  * than to the well-known name. As a result, the name owner will
2082  * not change over time, and the proxy will emit the "destroy" signal
2083  * when the owner disappears from the message bus.
2084  *
2085  * An example of the difference between dbus_g_proxy_new_for_name()
2086  * and dbus_g_proxy_new_for_name_owner(): if you provide the well-known name
2087  * "org.freedesktop.Database" dbus_g_proxy_new_for_name() remains bound
2088  * to that name as it changes owner. dbus_g_proxy_new_for_name_owner()
2089  * will fail if the name has no owner. If the name has an owner,
2090  * dbus_g_proxy_new_for_name_owner() will bind to the unique name
2091  * of that owner rather than the generic name.
2092  *
2093  * Returns: new proxy object, or %NULL on error
2094  *
2095  * Deprecated: New code should use GDBus instead. The closest equivalent
2096  *  is g_dbus_proxy_new_sync() with the name owner's unique name
2097  *  passed as @name.
2098  */
2099 DBusGProxy*
dbus_g_proxy_new_for_name_owner(DBusGConnection * connection,const char * name,const char * path,const char * iface,GError ** error)2100 dbus_g_proxy_new_for_name_owner (DBusGConnection          *connection,
2101                                  const char               *name,
2102                                  const char               *path,
2103                                  const char               *iface,
2104                                  GError                  **error)
2105 {
2106   DBusGProxy *proxy;
2107   char *unique_name;
2108 
2109   g_return_val_if_fail (connection != NULL, NULL);
2110   g_return_val_if_fail (g_dbus_is_name (name), NULL);
2111   g_return_val_if_fail (g_variant_is_object_path (path), NULL);
2112   g_return_val_if_fail (g_dbus_is_interface_name (iface), NULL);
2113 
2114   if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
2115     return NULL;
2116 
2117   proxy = dbus_g_proxy_new (connection, unique_name, path, iface);
2118   g_free (unique_name);
2119   return proxy;
2120 }
2121 
2122 /**
2123  * dbus_g_proxy_new_from_proxy:
2124  * @proxy: the proxy to use as a template
2125  * @iface: name of the interface to call methods on
2126  * @path: of the object inside the peer to call methods on
2127  *
2128  * Creates a proxy using an existing proxy as a template, substituting
2129  * the specified interface and path.  Either or both may be NULL.
2130  *
2131  * Returns: new proxy object
2132  *
2133  * Deprecated: New code should use GDBus instead. The closest equivalent
2134  *  is g_dbus_proxy_new_sync().
2135  */
2136 DBusGProxy*
dbus_g_proxy_new_from_proxy(DBusGProxy * proxy,const char * iface,const char * path)2137 dbus_g_proxy_new_from_proxy (DBusGProxy        *proxy,
2138 			     const char        *iface,
2139 			     const char        *path)
2140 {
2141   DBusGProxyPrivate *priv;
2142 
2143   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2144   g_return_val_if_fail (path == NULL || g_variant_is_object_path (path), NULL);
2145   g_return_val_if_fail (iface == NULL ||
2146       g_dbus_is_interface_name (iface), NULL);
2147 
2148   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2149 
2150   if (iface == NULL)
2151     iface = priv->interface;
2152   if (path == NULL)
2153     path = priv->path;
2154 
2155   return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
2156 			   priv->name,
2157 			   path, iface);
2158 }
2159 
2160 /**
2161  * dbus_g_proxy_new_for_peer:
2162  * @connection: the connection to the peer
2163  * @path: name of the object inside the peer to call methods on
2164  * @iface: name of the interface to call methods on
2165  *
2166  * Creates a proxy for an object in peer application (one
2167  * we're directly connected to). That is, this function is
2168  * intended for use when there's no message bus involved,
2169  * we're doing a simple 1-to-1 communication between two
2170  * applications.
2171  *
2172  * Returns: new proxy object
2173  *
2174  * Deprecated: New code should use GDBus instead. The closest equivalent
2175  *  is g_dbus_proxy_new_sync().
2176  */
2177 DBusGProxy*
dbus_g_proxy_new_for_peer(DBusGConnection * connection,const char * path,const char * iface)2178 dbus_g_proxy_new_for_peer (DBusGConnection          *connection,
2179                            const char               *path,
2180                            const char               *iface)
2181 {
2182   DBusGProxy *proxy;
2183 
2184   g_return_val_if_fail (connection != NULL, NULL);
2185   g_return_val_if_fail (g_variant_is_object_path (path), NULL);
2186   g_return_val_if_fail (g_dbus_is_interface_name (iface), NULL);
2187 
2188   proxy = dbus_g_proxy_new (connection, NULL, path, iface);
2189 
2190   return proxy;
2191 }
2192 
2193 /**
2194  * dbus_g_proxy_get_bus_name:
2195  * @proxy: the proxy
2196  *
2197  * Gets the bus name a proxy is bound to (may be %NULL in some cases).
2198  * If you created the proxy with dbus_g_proxy_new_for_name(), then
2199  * the name you passed to that will be returned.
2200  * If you created it with dbus_g_proxy_new_for_name_owner(), then the
2201  * unique connection name will be returned. If you created it
2202  * with dbus_g_proxy_new_for_peer() then %NULL will be returned.
2203  *
2204  * It is an error to call this method on a proxy that has emitted
2205  * the #DBusGProxy::destroy signal.
2206  *
2207  * Returns: the bus name the proxy sends messages to
2208  *
2209  * Deprecated: New code should use GDBus instead. The closest equivalent
2210  *  is g_dbus_proxy_get_name() or g_dbus_proxy_get_name_owner(),
2211  *  depending how the proxy was created.
2212  */
2213 const char*
dbus_g_proxy_get_bus_name(DBusGProxy * proxy)2214 dbus_g_proxy_get_bus_name (DBusGProxy        *proxy)
2215 {
2216   DBusGProxyPrivate *priv;
2217 
2218   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2219   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2220 
2221   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2222 
2223   return priv->name;
2224 }
2225 
2226 /**
2227  * dbus_g_proxy_get_interface:
2228  * @proxy: the proxy
2229  *
2230  * Gets the object interface proxy is bound to (may be %NULL in some cases).
2231  *
2232  * It is an error to call this method on a proxy that has emitted
2233  * the #DBusGProxy::destroy signal.
2234  *
2235  * Returns: an object interface
2236  *
2237  * Deprecated: New code should use GDBus instead. The closest equivalent
2238  *  is g_dbus_proxy_get_interface_name().
2239  */
2240 const char*
dbus_g_proxy_get_interface(DBusGProxy * proxy)2241 dbus_g_proxy_get_interface (DBusGProxy        *proxy)
2242 {
2243   DBusGProxyPrivate *priv;
2244 
2245   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2246   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2247 
2248   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2249 
2250   return priv->interface;
2251 }
2252 
2253 /**
2254  * dbus_g_proxy_set_interface:
2255  * @proxy: the proxy
2256  * @interface_name: an object interface
2257  *
2258  * Sets the object interface proxy is bound to
2259  *
2260  * It is an error to call this method on a proxy that has emitted
2261  * the #DBusGProxy::destroy signal.
2262  *
2263  * Deprecated: New code should use GDBus instead. There is no
2264  *  direct equivalent for this function: construct a new proxy instead.
2265  */
2266 void
dbus_g_proxy_set_interface(DBusGProxy * proxy,const char * interface_name)2267 dbus_g_proxy_set_interface (DBusGProxy        *proxy,
2268 			    const char        *interface_name)
2269 {
2270   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2271 
2272   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2273   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2274   g_return_if_fail (g_dbus_is_interface_name (interface_name));
2275 
2276   /* FIXME - need to unregister when we switch interface for now
2277    * later should support idea of unset interface
2278    */
2279   dbus_g_proxy_manager_unregister (priv->manager, proxy);
2280   g_free (priv->interface);
2281   priv->interface = g_strdup (interface_name);
2282   dbus_g_proxy_manager_register (priv->manager, proxy);
2283 }
2284 
2285 /**
2286  * dbus_g_proxy_get_path:
2287  * @proxy: the proxy
2288  *
2289  * Gets the path this proxy is bound to
2290  *
2291  * It is an error to call this method on a proxy that has emitted
2292  * the #DBusGProxy::destroy signal.
2293  *
2294  * Returns: an object path
2295  *
2296  * Deprecated: New code should use GDBus instead. The closest equivalent
2297  *  is g_dbus_proxy_get_object_path().
2298  */
2299 const char*
dbus_g_proxy_get_path(DBusGProxy * proxy)2300 dbus_g_proxy_get_path (DBusGProxy        *proxy)
2301 {
2302   DBusGProxyPrivate *priv;
2303 
2304   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2305   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2306 
2307   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2308 
2309   return priv->path;
2310 }
2311 
2312 static DBusMessage *
dbus_g_proxy_marshal_args_to_message(DBusGProxy * proxy,const char * method,GValueArray * args)2313 dbus_g_proxy_marshal_args_to_message (DBusGProxy  *proxy,
2314 				      const char  *method,
2315 				      GValueArray *args)
2316 {
2317   DBusMessage *message;
2318   DBusMessageIter msgiter;
2319   guint i;
2320   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2321 
2322   message = dbus_message_new_method_call (priv->name,
2323                                           priv->path,
2324                                           priv->interface,
2325                                           method);
2326   if (message == NULL)
2327     return NULL;
2328 
2329   dbus_message_iter_init_append (message, &msgiter);
2330   for (i = 0; i < args->n_values; i++)
2331     {
2332       GValue *gvalue;
2333 
2334       gvalue = g_value_array_get_nth (args, i);
2335 
2336       if (!_dbus_gvalue_marshal (&msgiter, gvalue))
2337         {
2338           /* This is a programming error by the caller, most likely */
2339           gchar *contents = g_strdup_value_contents (gvalue);
2340 
2341           g_critical ("Could not marshal argument %u for %s: type %s, value %s",
2342               i, method, G_VALUE_TYPE_NAME (gvalue), contents);
2343           g_free (contents);
2344           dbus_message_unref (message);
2345           return NULL;
2346         }
2347     }
2348 
2349   return message;
2350 }
2351 
2352 static guint
dbus_g_proxy_begin_call_internal(DBusGProxy * proxy,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,GValueArray * args,int timeout)2353 dbus_g_proxy_begin_call_internal (DBusGProxy          *proxy,
2354 				  const char          *method,
2355 				  DBusGProxyCallNotify notify,
2356 				  gpointer             user_data,
2357 				  GDestroyNotify       destroy,
2358 				  GValueArray         *args,
2359 				  int timeout)
2360 {
2361   DBusMessage *message;
2362   DBusPendingCall *pending;
2363   GPendingNotifyClosure *closure;
2364   guint call_id;
2365   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2366 
2367   pending = NULL;
2368 
2369   message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
2370 
2371   /* can only happen on a programming error or OOM; we already critical'd */
2372   if (!message)
2373     return 0;
2374 
2375   if (!dbus_connection_send_with_reply (priv->manager->connection,
2376                                         message,
2377                                         &pending,
2378                                         timeout))
2379     oom ();
2380 
2381   dbus_message_unref (message);
2382 
2383   /* If we got a NULL pending, that means the connection was disconnected,
2384    * and we need to abort this call.
2385    * https://bugs.freedesktop.org/show_bug.cgi?id=12675
2386    */
2387   if (pending == NULL)
2388     return 0;
2389 
2390   call_id = ++priv->call_id_counter;
2391 
2392   if (notify != NULL)
2393     {
2394       closure = g_new (GPendingNotifyClosure, 1);
2395       closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
2396       closure->call_id = call_id;
2397       closure->func = notify;
2398       closure->data = user_data;
2399       closure->free_data_func = destroy;
2400       dbus_pending_call_set_notify (pending, d_pending_call_notify,
2401 				    closure,
2402 				    d_pending_call_free);
2403     }
2404 
2405   g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
2406 
2407   return call_id;
2408 }
2409 
2410 static gboolean
dbus_g_proxy_end_call_internal(DBusGProxy * proxy,guint call_id,GError ** error,GType first_arg_type,va_list args)2411 dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
2412 				guint              call_id,
2413 				GError           **error,
2414 				GType              first_arg_type,
2415 				va_list            args)
2416 {
2417   DBusMessage *reply;
2418   DBusMessageIter msgiter;
2419   DBusError derror;
2420   va_list args_unwind;
2421   guint over;
2422   int n_retvals_processed;
2423   gboolean ret;
2424   GType valtype;
2425   DBusPendingCall *pending;
2426   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2427 
2428   if (call_id == 0)
2429     {
2430       /* Being disconnected is the only reason this can happen, except
2431        * for programmer error; if it was programmer error, we already
2432        * emitted a critical warning. */
2433       g_set_error (error, DBUS_GERROR, DBUS_GERROR_DISCONNECTED,
2434           "Disconnected from D-Bus (or argument error during call)");
2435       return FALSE;
2436     }
2437 
2438   reply = NULL;
2439   ret = FALSE;
2440   n_retvals_processed = 0;
2441   over = 0;
2442 
2443   /* Keep around a copy of output arguments so we can free on error. */
2444   G_VA_COPY(args_unwind, args);
2445 
2446   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
2447 
2448   dbus_pending_call_block (pending);
2449   reply = dbus_pending_call_steal_reply (pending);
2450 
2451   g_assert (reply != NULL);
2452 
2453   dbus_error_init (&derror);
2454 
2455   switch (dbus_message_get_type (reply))
2456     {
2457     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
2458       dbus_message_iter_init (reply, &msgiter);
2459       valtype = first_arg_type;
2460       while (valtype != G_TYPE_INVALID)
2461 	{
2462 	  int arg_type;
2463 	  gpointer return_storage;
2464 	  GValue gvalue = { 0, };
2465 	  DBusGValueMarshalCtx context;
2466 
2467           context.recursion_depth = 0;
2468 	  context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
2469 	  context.proxy = proxy;
2470 
2471 	  arg_type = dbus_message_iter_get_arg_type (&msgiter);
2472 	  if (arg_type == DBUS_TYPE_INVALID)
2473 	    {
2474 	      g_set_error (error, DBUS_GERROR,
2475 			   DBUS_GERROR_INVALID_ARGS,
2476 			   "Too few arguments in reply");
2477 	      goto out;
2478 	    }
2479 
2480 	  return_storage = va_arg (args, gpointer);
2481 	  if (return_storage == NULL)
2482 	    goto next;
2483 
2484 	  /* We handle variants specially; the caller is expected
2485 	   * to have already allocated storage for them.
2486 	   */
2487 	  if (arg_type == DBUS_TYPE_VARIANT
2488 	      && g_type_is_a (valtype, G_TYPE_VALUE))
2489 	    {
2490 	      if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
2491 		{
2492 		  g_set_error (error,
2493 			       DBUS_GERROR,
2494 			       DBUS_GERROR_INVALID_ARGS,
2495 			       "Couldn't convert argument, expected \"%s\"",
2496 			       g_type_name (valtype));
2497 		  goto out;
2498 		}
2499 	    }
2500 	  else
2501 	    {
2502 	      g_value_init (&gvalue, valtype);
2503 
2504 	      if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
2505 		goto out;
2506 
2507 	      /* Anything that can be demarshaled must be storable */
2508 	      if (!_dbus_gvalue_store (&gvalue, return_storage))
2509 		g_assert_not_reached ();
2510 	      /* Ownership of the value passes to the client, don't unset */
2511 	    }
2512 
2513 	next:
2514 	  n_retvals_processed++;
2515 	  dbus_message_iter_next (&msgiter);
2516 	  valtype = va_arg (args, GType);
2517 	}
2518 
2519       while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
2520 	{
2521 	  over++;
2522 	  dbus_message_iter_next (&msgiter);
2523 	}
2524 
2525       if (over > 0)
2526 	{
2527 	  g_set_error (error, DBUS_GERROR,
2528 		       DBUS_GERROR_INVALID_ARGS,
2529 		       "Too many arguments in reply; expected %d, got %d",
2530 		       n_retvals_processed, over);
2531 	  goto out;
2532 	}
2533       break;
2534     case DBUS_MESSAGE_TYPE_ERROR:
2535       dbus_set_error_from_message (&derror, reply);
2536       dbus_set_g_error (error, &derror);
2537       dbus_error_free (&derror);
2538       goto out;
2539       break;
2540     default:
2541       dbus_set_error (&derror, DBUS_ERROR_FAILED,
2542                       "Reply was neither a method return nor an exception");
2543       dbus_set_g_error (error, &derror);
2544       dbus_error_free (&derror);
2545       goto out;
2546       break;
2547     }
2548 
2549   ret = TRUE;
2550  out:
2551   if (ret == FALSE)
2552     {
2553       int i;
2554 
2555       valtype = first_arg_type;
2556       for (i = 0; i < n_retvals_processed; i++)
2557 	{
2558           GValue value = {0,};
2559 	  gpointer retval;
2560 
2561           g_value_init (&value, valtype);
2562 
2563 	  retval = va_arg (args_unwind, gpointer);
2564           if (retval == NULL)
2565             {
2566               i--;
2567               continue;
2568             }
2569 
2570           _dbus_gvalue_take (&value, retval);
2571           g_value_unset (&value);
2572 
2573           valtype = va_arg (args_unwind, GType);
2574 	}
2575     }
2576   va_end (args_unwind);
2577   va_end (args);
2578 
2579   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
2580 
2581   if (reply)
2582     dbus_message_unref (reply);
2583   return ret;
2584 }
2585 
2586 /**
2587  * dbus_g_proxy_begin_call:
2588  * @proxy: a proxy for a remote interface
2589  * @method: the name of the method to invoke
2590  * @notify: callback to be invoked when method returns
2591  * @user_data: user data passed to callback
2592  * @destroy: function called to destroy user_data
2593  * @first_arg_type: type of the first argument, or %G_TYPE_INVALID if there
2594  *    are no arguments
2595  * @...: first argument, followed by any further type/value pairs, followed
2596  *    by %G_TYPE_INVALID
2597  *
2598  * Asynchronously invokes a method on a remote interface. The method
2599  * call will not be sent over the wire until the application returns
2600  * to the main loop, or blocks in dbus_g_connection_flush() to write out
2601  * pending data.  The call will be completed after a timeout, or when
2602  * a reply is received.  When the call returns, the callback specified
2603  * will be invoked; you can then collect the results of the call
2604  * (which may be an error, or a reply), use dbus_g_proxy_end_call().
2605  *
2606  * It is an error to call this method on a proxy that has emitted
2607  * the #DBusGProxy::destroy signal.
2608  *
2609  * TODO this particular function shouldn't die on out of memory,
2610  * since you should be able to do a call with large arguments.
2611  *
2612  * Returns: call identifier.
2613  *
2614  * Deprecated: New code should use GDBus instead. The closest equivalent
2615  *  is g_dbus_proxy_call().
2616  */
2617 DBusGProxyCall *
dbus_g_proxy_begin_call(DBusGProxy * proxy,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,GType first_arg_type,...)2618 dbus_g_proxy_begin_call (DBusGProxy          *proxy,
2619 			 const char          *method,
2620 			 DBusGProxyCallNotify notify,
2621 			 gpointer             user_data,
2622 			 GDestroyNotify       destroy,
2623 			 GType                first_arg_type,
2624 			 ...)
2625 {
2626   guint call_id = 0;
2627   va_list args;
2628   GValueArray *arg_values;
2629   DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2630 
2631   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2632   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2633   g_return_val_if_fail (g_dbus_is_member_name (method), NULL);
2634 
2635   va_start (args, first_arg_type);
2636 
2637   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
2638 
2639   if (arg_values != NULL)
2640     {
2641       call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify,
2642           user_data, destroy, arg_values, priv->default_timeout);
2643 
2644       g_value_array_free (arg_values);
2645     }
2646 
2647   va_end (args);
2648 
2649   return DBUS_G_PROXY_ID_TO_CALL (call_id);
2650 }
2651 
2652 /**
2653  * dbus_g_proxy_begin_call_with_timeout:
2654  * @proxy: a proxy for a remote interface
2655  * @method: the name of the method to invoke
2656  * @notify: callback to be invoked when method returns
2657  * @user_data: user data passed to callback
2658  * @destroy: function called to destroy user_data
2659  * @timeout: the timeout in milliseconds, or -1 to use a default
2660  * @first_arg_type: type of the first argument, or %G_TYPE_INVALID if there
2661  *    are no arguments
2662  * @...: first argument, followed by any further type/value pairs, followed
2663  *    by %G_TYPE_INVALID
2664  *
2665  * Asynchronously invokes a method on a remote interface. The method
2666  * call will not be sent over the wire until the application returns
2667  * to the main loop, or blocks in dbus_g_connection_flush() to write out
2668  * pending data.  The call will be completed after a timeout, or when
2669  * a reply is received.  When the call returns, the callback specified
2670  * will be invoked; you can then collect the results of the call
2671  * (which may be an error, or a reply), use dbus_g_proxy_end_call().
2672  *
2673  * It is an error to call this method on a proxy that has emitted
2674  * the #DBusGProxy::destroy signal.
2675  *
2676  * TODO this particular function shouldn't die on out of memory,
2677  * since you should be able to do a call with large arguments.
2678  *
2679  * Returns: call identifier.
2680  *
2681  * Deprecated: New code should use GDBus instead. The closest equivalent
2682  *  is g_dbus_proxy_call().
2683  */
2684 DBusGProxyCall *
dbus_g_proxy_begin_call_with_timeout(DBusGProxy * proxy,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,int timeout,GType first_arg_type,...)2685 dbus_g_proxy_begin_call_with_timeout (DBusGProxy          *proxy,
2686                          const char          *method,
2687                          DBusGProxyCallNotify notify,
2688                          gpointer             user_data,
2689                          GDestroyNotify       destroy,
2690 			 int timeout,
2691                          GType                first_arg_type,
2692                          ...)
2693 {
2694   guint call_id = 0;
2695   va_list args;
2696   GValueArray *arg_values;
2697 
2698   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2699   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2700   g_return_val_if_fail (g_dbus_is_member_name (method), NULL);
2701   g_return_val_if_fail (timeout >= 0 || timeout == -1, NULL);
2702 
2703   va_start (args, first_arg_type);
2704 
2705   DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
2706 
2707   if (arg_values != NULL)
2708     {
2709       call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify,
2710           user_data, destroy, arg_values, timeout);
2711 
2712       g_value_array_free (arg_values);
2713     }
2714 
2715   va_end (args);
2716 
2717   return DBUS_G_PROXY_ID_TO_CALL (call_id);
2718 }
2719 
2720 /**
2721  * dbus_g_proxy_end_call:
2722  * @proxy: a proxy for a remote interface
2723  * @call: the pending call ID from dbus_g_proxy_begin_call()
2724  * @error: return location for an error
2725  * @first_arg_type: type of first "out" argument, or %G_TYPE_INVALID if
2726  *    there are no "out" arguments
2727  * @...: return location for first "out" argument, followed by any further
2728  *    type/location pairs, followed by %G_TYPE_INVALID
2729  *
2730  * Collects the results of a method call. The method call was normally
2731  * initiated with dbus_g_proxy_end_call(). You may use this function
2732  * outside of the callback given to dbus_g_proxy_begin_call; in that
2733  * case this function will block if the results haven't yet been
2734  * received.
2735  *
2736  * All D-Bus method calls can fail with a remote error. If this occurs,
2737  * the @error will be set and this function will return %FALSE.
2738  *
2739  * Otherwise, the "out" parameters and return value of the
2740  * method are stored in the provided varargs list.
2741  * The list should be terminated with G_TYPE_INVALID.
2742  *
2743  * Returns: %TRUE on success
2744  *
2745  * Deprecated: New code should use GDBus instead. The closest equivalent
2746  *  is g_dbus_proxy_call_finish().
2747  */
2748 gboolean
dbus_g_proxy_end_call(DBusGProxy * proxy,DBusGProxyCall * call,GError ** error,GType first_arg_type,...)2749 dbus_g_proxy_end_call (DBusGProxy          *proxy,
2750                        DBusGProxyCall      *call,
2751                        GError             **error,
2752                        GType                first_arg_type,
2753                        ...)
2754 {
2755   gboolean ret;
2756   va_list args;
2757 
2758   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2759 
2760   va_start (args, first_arg_type);
2761 
2762   ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
2763 
2764   va_end (args);
2765 
2766   return ret;
2767 }
2768 
2769 /**
2770  * dbus_g_proxy_call:
2771  * @proxy: a proxy for a remote interface
2772  * @method: method to invoke
2773  * @error: return location for an error
2774  * @first_arg_type: type of first "in" argument, or %G_TYPE_INVALID if none
2775  * @...: value of first "in" argument, any further type/value pairs,
2776  *    %G_TYPE_INVALID, type/location pairs for "out" arguments,
2777  *    and %G_TYPE_INVALID again
2778  *
2779  * Function for synchronously invoking a method and receiving reply
2780  * values.  This function is equivalent to dbus_g_proxy_begin_call
2781  * followed by dbus_g_proxy_end_call.  All of the input arguments are
2782  * specified first, followed by G_TYPE_INVALID, followed by all of the
2783  * output values, followed by a second G_TYPE_INVALID.  Note that
2784  * this means you must always specify G_TYPE_INVALID twice.
2785  *
2786  * It is an error to call this method on a proxy that has emitted
2787  * the #DBusGProxy::destroy signal.
2788  *
2789  * Returns: %TRUE if the method succeeds, %FALSE if it fails
2790  *
2791  * Deprecated: New code should use GDBus instead. The closest equivalent
2792  *  is g_dbus_proxy_call_sync().
2793  */
2794 gboolean
dbus_g_proxy_call(DBusGProxy * proxy,const char * method,GError ** error,GType first_arg_type,...)2795 dbus_g_proxy_call (DBusGProxy        *proxy,
2796 		   const char        *method,
2797 		   GError           **error,
2798 		   GType              first_arg_type,
2799 		   ...)
2800 {
2801   gboolean ret;
2802   guint call_id = 0;
2803   va_list args;
2804   GValueArray *in_args;
2805   DBusGProxyPrivate *priv;
2806 
2807   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2808   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
2809 
2810   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2811 
2812   va_start (args, first_arg_type);
2813 
2814   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2815 
2816   if (in_args != NULL)
2817     {
2818       call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL,
2819           NULL, in_args, priv->default_timeout);
2820 
2821       g_value_array_free (in_args);
2822     }
2823 
2824   first_arg_type = va_arg (args, GType);
2825   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type,
2826       args);
2827 
2828   va_end (args);
2829 
2830   return ret;
2831 }
2832 
2833 /**
2834  * dbus_g_proxy_call_with_timeout:
2835  * @proxy: a proxy for a remote interface
2836  * @method: method to invoke
2837  * @timeout: the timeout in milliseconds, or -1 to use a default
2838  * @error: return location for an error
2839  * @first_arg_type: type of first "in" argument
2840  * @...: as for dbus_g_proxy_call()
2841  *
2842  * Function for synchronously invoking a method and receiving reply
2843  * values.  This function is equivalent to dbus_g_proxy_begin_call
2844  * followed by dbus_g_proxy_end_call.  All of the input arguments are
2845  * specified first, followed by G_TYPE_INVALID, followed by all of the
2846  * output values, followed by a second G_TYPE_INVALID.  Note that
2847  * this means you must always specify G_TYPE_INVALID twice.
2848  *
2849  * It is an error to call this method on a proxy that has emitted
2850  * the #DBusGProxy::destroy signal.
2851  *
2852  * Returns: %TRUE if the method succeeds, %FALSE if it fails
2853  *
2854  * Deprecated: New code should use GDBus instead. The closest equivalent
2855  *  is g_dbus_proxy_call_sync().
2856  */
2857 gboolean
dbus_g_proxy_call_with_timeout(DBusGProxy * proxy,const char * method,int timeout,GError ** error,GType first_arg_type,...)2858 dbus_g_proxy_call_with_timeout (DBusGProxy        *proxy,
2859                    const char        *method,
2860 		   int timeout,
2861                    GError           **error,
2862                    GType              first_arg_type,
2863                    ...)
2864 {
2865   gboolean ret;
2866   guint call_id = 0;
2867   va_list args;
2868   GValueArray *in_args;
2869 
2870   g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2871   g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
2872   g_return_val_if_fail (g_dbus_is_member_name (method), FALSE);
2873   g_return_val_if_fail (timeout >= 0 || timeout == -1, FALSE);
2874 
2875   va_start (args, first_arg_type);
2876 
2877   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2878 
2879   if (in_args != NULL)
2880     {
2881       call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL,
2882           NULL, in_args, timeout);
2883 
2884       g_value_array_free (in_args);
2885     }
2886 
2887   first_arg_type = va_arg (args, GType);
2888   ret = dbus_g_proxy_end_call_internal (proxy, call_id, error,
2889       first_arg_type, args);
2890 
2891   va_end (args);
2892 
2893   return ret;
2894 }
2895 
2896 /**
2897  * dbus_g_proxy_call_no_reply:
2898  * @proxy: a proxy for a remote interface
2899  * @method: the name of the method to invoke
2900  * @first_arg_type: type of the first argument, or %G_TYPE_INVALID to call
2901  *    the method without arguments
2902  * @...: the first argument and any remaining type/argument pairs, followed by
2903  *    %G_TYPE_INVALID to terminate the list
2904  *
2905  * Sends a method call message as with dbus_g_proxy_begin_call(), but
2906  * does not ask for a reply or allow you to receive one.
2907  *
2908  * It is an error to call this method on a proxy that has emitted
2909  * the #DBusGProxy::destroy signal.
2910  *
2911  * TODO: this particular function shouldn't die on out of memory,
2912  * since you should be able to do a call with large arguments.
2913  *
2914  * Deprecated: New code should use GDBus instead. The closest equivalent
2915  *  is g_dbus_proxy_call() with @callback = %NULL.
2916  */
2917 void
dbus_g_proxy_call_no_reply(DBusGProxy * proxy,const char * method,GType first_arg_type,...)2918 dbus_g_proxy_call_no_reply (DBusGProxy               *proxy,
2919 			    const char               *method,
2920 			    GType                     first_arg_type,
2921 			    ...)
2922 {
2923   DBusMessage *message = NULL;
2924   va_list args;
2925   GValueArray *in_args;
2926   DBusGProxyPrivate *priv;
2927 
2928   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2929   g_return_if_fail (g_dbus_is_member_name (method));
2930   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2931 
2932   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2933 
2934   va_start (args, first_arg_type);
2935   DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2936 
2937   if (in_args != NULL)
2938     {
2939       message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
2940 
2941       g_value_array_free (in_args);
2942     }
2943 
2944   va_end (args);
2945 
2946   /* can only happen on a programming error or OOM; we already critical'd */
2947   if (!message)
2948     return;
2949 
2950   dbus_message_set_no_reply (message, TRUE);
2951 
2952   if (!dbus_connection_send (priv->manager->connection,
2953                              message,
2954                              NULL))
2955     oom ();
2956 
2957   dbus_message_unref (message);
2958 }
2959 
2960 /**
2961  * dbus_g_proxy_cancel_call
2962  * @proxy: a proxy for a remote interface
2963  * @call: the pending call ID from dbus_g_proxy_begin_call()
2964  *
2965  * Cancels a pending method call. The method call was normally
2966  * initiated with dbus_g_proxy_begin_call().  This function
2967  * may not be used on pending calls that have already been
2968  * ended with dbus_g_proxy_end_call.
2969  *
2970  * It is an error to call this method on a proxy that has emitted
2971  * the #DBusGProxy::destroy signal.
2972  *
2973  * Deprecated: New code should use GDBus instead. The closest equivalent
2974  *  is g_cancellable_cancel().
2975  */
2976 void
dbus_g_proxy_cancel_call(DBusGProxy * proxy,DBusGProxyCall * call)2977 dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
2978 			  DBusGProxyCall    *call)
2979 {
2980   guint call_id;
2981   DBusPendingCall *pending;
2982   DBusGProxyPrivate *priv;
2983 
2984   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2985   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2986 
2987   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2988 
2989   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
2990 
2991   if (call_id == 0)
2992     {
2993       /* nothing to cancel */
2994       return;
2995     }
2996 
2997   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
2998   g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
2999   g_return_if_fail (pending != NULL);
3000 
3001   dbus_pending_call_cancel (pending);
3002 }
3003 
3004 /**
3005  * dbus_g_proxy_send:
3006  * @proxy: a proxy for a remote interface
3007  * @message: the message to address and send
3008  * @client_serial: return location for message's serial, or %NULL
3009  *
3010  * Sends a message to the interface we're proxying for.  Does not
3011  * block or wait for a reply. The message is only actually written out
3012  * when you return to the main loop or block in
3013  * dbus_g_connection_flush().
3014  *
3015  * The message is modified to be addressed to the target interface.
3016  * That is, a destination name field or whatever is needed will be
3017  * added to the message. The basic point of this function is to add
3018  * the necessary header fields, otherwise it's equivalent to
3019  * dbus_connection_send().
3020  *
3021  * This function adds a reference to the message, so the caller
3022  * still owns its original reference.
3023  *
3024  * It is an error to call this method on a proxy that has emitted
3025  * the #DBusGProxy::destroy signal.
3026  *
3027  * Deprecated: New code should use GDBus instead. The closest equivalent
3028  *  is g_dbus_connection_send_message().
3029  */
3030 void
dbus_g_proxy_send(DBusGProxy * proxy,DBusMessage * message,dbus_uint32_t * client_serial)3031 dbus_g_proxy_send (DBusGProxy          *proxy,
3032                    DBusMessage         *message,
3033                    dbus_uint32_t       *client_serial)
3034 {
3035   DBusGProxyPrivate *priv;
3036 
3037   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3038   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3039 
3040   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3041 
3042   if (priv->name)
3043     {
3044       if (!dbus_message_set_destination (message, priv->name))
3045         g_error ("Out of memory");
3046     }
3047   if (priv->path)
3048     {
3049       if (!dbus_message_set_path (message, priv->path))
3050         g_error ("Out of memory");
3051     }
3052   if (priv->interface)
3053     {
3054       if (!dbus_message_set_interface (message, priv->interface))
3055         g_error ("Out of memory");
3056     }
3057 
3058   if (!dbus_connection_send (priv->manager->connection, message, client_serial))
3059     g_error ("Out of memory\n");
3060 }
3061 
3062 static void
array_free_all(gpointer array)3063 array_free_all (gpointer array)
3064 {
3065   g_array_free (array, TRUE);
3066 }
3067 
3068 /**
3069  * dbus_g_proxy_add_signal:
3070  * @proxy: the proxy for a remote interface
3071  * @signal_name: the name of the signal
3072  * @first_type: the first argument type, or %G_TYPE_INVALID if none
3073  * @...: any subsequent argument types, followed by %G_TYPE_INVALID
3074  *
3075  * Specifies the argument signature of a D-Bus signal. When the signal is
3076  * emitted by the remote object, if the GTypes corresponding to its arguments'
3077  * types do not match the types given here, the signal will be ignored.
3078  *
3079  * It is an error to add the same @signal_name to the same @proxy more than
3080  * once, even if the argument types given are the same.
3081  *
3082  * It is also an error to call this method on a proxy that has emitted
3083  * the #DBusGProxy::destroy signal.
3084  *
3085  * Deprecated: New code should use GDBus instead.
3086  */
3087 void
dbus_g_proxy_add_signal(DBusGProxy * proxy,const char * signal_name,GType first_type,...)3088 dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
3089                           const char        *signal_name,
3090 			  GType              first_type,
3091                           ...)
3092 {
3093   GQuark q;
3094   char *name;
3095   GArray *gtypesig;
3096   GType gtype;
3097   va_list args;
3098   DBusGProxyPrivate *priv;
3099 
3100   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3101   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3102   g_return_if_fail (g_dbus_is_member_name (signal_name));
3103 
3104   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3105 
3106   name = create_signal_name (priv->interface, signal_name);
3107 
3108   q = g_quark_from_string (name);
3109 
3110   g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
3111 
3112   gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
3113 
3114   va_start (args, first_type);
3115   gtype = first_type;
3116   while (gtype != G_TYPE_INVALID)
3117     {
3118       g_array_append_val (gtypesig, gtype);
3119       gtype = va_arg (args, GType);
3120     }
3121   va_end (args);
3122 
3123   g_datalist_id_set_data_full (&priv->signal_signatures,
3124                                q, gtypesig,
3125                                array_free_all);
3126 
3127   g_free (name);
3128 }
3129 
3130 /**
3131  * dbus_g_proxy_connect_signal:
3132  * @proxy: a proxy for a remote interface
3133  * @signal_name: the DBus signal name to listen for
3134  * @handler: the handler to connect
3135  * @data: data to pass to handler
3136  * @free_data_func: callback function to destroy data
3137  *
3138  * Connect a signal handler to a proxy for a remote interface.  When
3139  * the remote interface emits the specified signal, the proxy will
3140  * emit a corresponding GLib signal.
3141  *
3142  * It is an error to call this method on a proxy that has emitted
3143  * the #DBusGProxy::destroy signal.
3144  *
3145  * Deprecated: New code should use GDBus instead. The closest equivalent
3146  *  is g_dbus_connection_signal_subscribe().
3147  */
3148 void
dbus_g_proxy_connect_signal(DBusGProxy * proxy,const char * signal_name,GCallback handler,void * data,GClosureNotify free_data_func)3149 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
3150                              const char             *signal_name,
3151                              GCallback               handler,
3152                              void                   *data,
3153                              GClosureNotify          free_data_func)
3154 {
3155   char *name;
3156   GClosure *closure;
3157   GQuark q;
3158   DBusGProxyPrivate *priv;
3159 
3160   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3161   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3162   g_return_if_fail (g_dbus_is_member_name (signal_name));
3163   g_return_if_fail (handler != NULL);
3164 
3165   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3166   name = create_signal_name (priv->interface, signal_name);
3167 
3168   q = g_quark_try_string (name);
3169 
3170 #ifndef G_DISABLE_CHECKS
3171   if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
3172     {
3173       g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
3174       g_free (name);
3175       return;
3176     }
3177 #endif
3178 
3179   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
3180 
3181   g_signal_connect_closure_by_id (G_OBJECT (proxy),
3182                                   signals[RECEIVED],
3183                                   q,
3184                                   closure, FALSE);
3185 
3186   g_free (name);
3187 }
3188 
3189 /**
3190  * dbus_g_proxy_disconnect_signal:
3191  * @proxy: a proxy for a remote interface
3192  * @signal_name: the DBus signal name to disconnect
3193  * @handler: the handler to disconnect
3194  * @data: the data that was registered with handler
3195  *
3196  * Disconnect all signal handlers from a proxy that match the given
3197  * criteria.
3198  *
3199  * It is an error to call this method on a proxy that has emitted
3200  * the #DBusGProxy::destroy signal.
3201  *
3202  * Deprecated: New code should use GDBus instead. The closest equivalent
3203  *  is g_dbus_connection_signal_unsubscribe().
3204  */
3205 void
dbus_g_proxy_disconnect_signal(DBusGProxy * proxy,const char * signal_name,GCallback handler,void * data)3206 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
3207                                 const char             *signal_name,
3208                                 GCallback               handler,
3209                                 void                   *data)
3210 {
3211   char *name;
3212   GQuark q;
3213   DBusGProxyPrivate *priv;
3214 
3215   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3216   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3217   g_return_if_fail (g_dbus_is_member_name (signal_name));
3218   g_return_if_fail (handler != NULL);
3219 
3220   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3221   name = create_signal_name (priv->interface, signal_name);
3222 
3223   q = g_quark_try_string (name);
3224 
3225   if (q != 0)
3226     {
3227       g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
3228                                             G_SIGNAL_MATCH_DETAIL |
3229                                             G_SIGNAL_MATCH_FUNC   |
3230                                             G_SIGNAL_MATCH_DATA,
3231                                             signals[RECEIVED],
3232                                             q,
3233                                             NULL,
3234                                             G_CALLBACK (handler), data);
3235     }
3236   else
3237     {
3238       g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
3239                  name);
3240     }
3241 
3242   g_free (name);
3243 }
3244 
3245 /**
3246  * dbus_g_proxy_set_default_timeout:
3247  * @proxy: a proxy for a remote interface
3248  * @timeout: the timeout in milliseconds, or -1 to reset to the libdbus default
3249  *
3250  * Sets the default timeout to use for a proxy. This timeout will be
3251  * used in calls where the timeout is not specified, or is specified to be -1.
3252  * If this timeout is also set to -1, libdbus will use a reasonable default
3253  * value.
3254  *
3255  * This is useful for long-running operations that takes longer than
3256  * the default timeout (which is a on the order of magnitude of tens
3257  * of seconds). For some applications, consider using a pattern where
3258  * the method returns once the operation is underway
3259  * (e.g. immediately) and emits a signal when the operation terminates
3260  * (though beware of leaking information with/in the signal return value).
3261  *
3262  * It is an error to call this method on a proxy that has emitted
3263  * the #DBusGProxy::destroy signal.
3264  *
3265  * Since: 0.75
3266  *
3267  * Deprecated: New code should use GDBus instead.
3268  */
3269 void
dbus_g_proxy_set_default_timeout(DBusGProxy * proxy,int timeout)3270 dbus_g_proxy_set_default_timeout (DBusGProxy        *proxy,
3271                                   int                timeout)
3272 {
3273   DBusGProxyPrivate *priv;
3274 
3275   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3276   g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3277   g_return_if_fail (timeout >= 0 || timeout == -1);
3278 
3279   priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3280   priv->default_timeout = timeout;
3281 }
3282