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