Modified to support char type.
[platform/upstream/dbus.git] / glib / dbus-gproxy.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gcall.c convenience routines for calling methods, etc.
3  *
4  * Copyright (C) 2003  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.0
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "dbus-glib.h"
24 #include <string.h>
25
26 /**
27  * @addtogroup DBusGLibInternals
28  *
29  * @{
30  */
31
32 typedef struct DBusGProxyManager DBusGProxyManager;
33
34 /**
35  * Internals of DBusGProxy
36  */
37 struct DBusGProxy
38 {
39   GObject parent;             /**< Parent instance */
40   
41   DBusGProxyManager *manager; /**< Proxy manager */
42   char *service;              /**< Service messages go to or NULL */
43   char *path;                 /**< Path messages go to or NULL */
44   char *interface;            /**< Interface messages go to or NULL */
45 };
46
47 /**
48  * Class struct for DBusGProxy
49  */
50 struct DBusGProxyClass
51 {
52   GObjectClass parent_class;  
53 };
54
55 static void dbus_gproxy_init          (DBusGProxy      *proxy);
56 static void dbus_gproxy_class_init    (DBusGProxyClass *klass);
57 static void dbus_gproxy_finalize      (GObject         *object);
58 static void dbus_gproxy_dispose       (GObject         *object);
59 static void dbus_gproxy_destroy       (DBusGProxy      *proxy);
60 static void dbus_gproxy_emit_received (DBusGProxy      *proxy,
61                                        DBusMessage     *message);
62
63
64 /**
65  * A list of proxies with a given service+path+interface, used to route incoming
66  * signals.
67  */
68 typedef struct
69 {
70   GSList *proxies;
71
72   char name[4]; /**< service (empty string for none), nul byte,
73                  *   path, nul byte,
74                  *   interface, nul byte
75                  */
76   
77 } DBusGProxyList;
78
79 /**
80  * DBusGProxyManager's primary task is to route signals to the proxies
81  * those signals are emitted on. In order to do this it also has to
82  * track the owners of the services proxies are bound to.
83  */
84 struct DBusGProxyManager
85 {
86   GStaticMutex lock; /**< Thread lock */
87   int refcount;      /**< Reference count */
88   DBusConnection *connection; /**< Connection we're associated with. */
89
90   GHashTable *proxy_lists; /**< Hash used to route incoming signals
91                             *   and iterate over proxies
92                             */
93
94 };
95
96 static DBusGProxyManager *dbus_gproxy_manager_ref    (DBusGProxyManager *manager);
97 static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection    *connection,
98                                                      DBusMessage       *message,
99                                                      void              *user_data);
100
101 /** Lock the DBusGProxyManager */
102 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
103 /** Unlock the DBusGProxyManager */
104 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
105
106 static int gproxy_manager_slot = -1;
107
108 /* Lock controlling get/set manager as data on each connection */
109 static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT;
110
111 static DBusGProxyManager*
112 dbus_gproxy_manager_get (DBusConnection *connection)
113 {
114   DBusGProxyManager *manager;
115
116   dbus_connection_allocate_data_slot (&gproxy_manager_slot);
117   if (gproxy_manager_slot < 0)
118     g_error ("out of memory");
119   
120   g_static_mutex_lock (&connection_gproxy_lock);
121   
122   manager = dbus_connection_get_data (connection, gproxy_manager_slot);
123   if (manager != NULL)
124     {
125       dbus_connection_free_data_slot (&gproxy_manager_slot);
126       dbus_gproxy_manager_ref (manager);
127       g_static_mutex_unlock (&connection_gproxy_lock);
128       return manager;
129     }
130   
131   manager = g_new0 (DBusGProxyManager, 1);
132
133   manager->refcount = 1;
134   manager->connection = connection;
135   
136   g_static_mutex_init (&manager->lock);
137
138   /* Proxy managers keep the connection alive, which means that
139    * DBusGProxy indirectly does. To free a connection you have to free
140    * all the proxies referring to it.
141    */
142   dbus_connection_ref (manager->connection);
143
144   dbus_connection_set_data (connection, gproxy_manager_slot,
145                             manager, NULL);
146
147   dbus_connection_add_filter (connection, dbus_gproxy_manager_filter,
148                               manager, NULL);
149   
150   g_static_mutex_unlock (&connection_gproxy_lock);
151   
152   return manager;
153 }
154
155 static DBusGProxyManager * 
156 dbus_gproxy_manager_ref (DBusGProxyManager *manager)
157 {
158   g_assert (manager != NULL);
159   g_assert (manager->refcount > 0);
160
161   LOCK_MANAGER (manager);
162   
163   manager->refcount += 1;
164
165   UNLOCK_MANAGER (manager);
166
167   return manager;
168 }
169
170 static void
171 dbus_gproxy_manager_unref (DBusGProxyManager *manager)
172 {
173   g_assert (manager != NULL);
174   g_assert (manager->refcount > 0);
175
176   LOCK_MANAGER (manager);
177   manager->refcount -= 1;
178   if (manager->refcount == 0)
179     {
180       UNLOCK_MANAGER (manager);
181
182       if (manager->proxy_lists)
183         {
184           /* can't have any proxies left since they hold
185            * a reference to the proxy manager.
186            */
187           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
188           
189           g_hash_table_destroy (manager->proxy_lists);
190           manager->proxy_lists = NULL;
191         }
192       
193       g_static_mutex_free (&manager->lock);
194
195       g_static_mutex_lock (&connection_gproxy_lock);
196
197       dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter,
198                                      manager);
199       
200       dbus_connection_set_data (manager->connection,
201                                 gproxy_manager_slot,
202                                 NULL, NULL);
203
204       g_static_mutex_unlock (&connection_gproxy_lock);
205       
206       dbus_connection_unref (manager->connection);
207       g_free (manager);
208
209       dbus_connection_free_data_slot (&gproxy_manager_slot);
210     }
211   else
212     {
213       UNLOCK_MANAGER (manager);
214     }
215 }
216
217 static guint
218 tristring_hash (gconstpointer key)
219 {
220   const char *p = key;
221   guint h = *p;
222
223   if (h)
224     {
225       for (p += 1; *p != '\0'; p++)
226         h = (h << 5) - h + *p;
227     }
228
229   /* skip nul and do the next substring */
230   for (p += 1; *p != '\0'; p++)
231     h = (h << 5) - h + *p;
232
233   /* skip nul again and another substring */
234   for (p += 1; *p != '\0'; p++)
235     h = (h << 5) - h + *p;
236   
237   return h;
238 }
239
240 static gboolean
241 strequal_len (const char *a,
242               const char *b,
243               size_t     *lenp)
244 {
245   size_t a_len;
246   size_t b_len;
247
248   a_len = strlen (a);
249   b_len = strlen (b);
250
251   if (a_len != b_len)
252     return FALSE;
253
254   if (memcmp (a, b, a_len) != 0)
255     return FALSE;
256   
257   *lenp = a_len;
258
259   return TRUE;
260 }
261
262 static gboolean
263 tristring_equal (gconstpointer  a,
264                  gconstpointer  b)
265 {
266   const char *ap = a;
267   const char *bp = b;
268   size_t len;
269
270   if (!strequal_len (ap, bp, &len))
271     return FALSE;
272
273   ap += len + 1;
274   bp += len + 1;
275
276   if (!strequal_len (ap, bp, &len))
277     return FALSE;
278
279   ap += len + 1;
280   bp += len + 1;
281
282   if (strcmp (ap, bp) != 0)
283     return FALSE;
284   
285   return TRUE;
286 }
287
288 static char*
289 tristring_alloc_from_strings (size_t      padding_before,
290                               const char *service,
291                               const char *path,
292                               const char *interface)
293 {
294   size_t service_len, iface_len, path_len, len;
295   char *tri;
296   
297   if (service)
298     service_len = strlen (service);
299   else
300     service_len = 0;
301
302   path_len = strlen (path);
303   
304   iface_len = strlen (interface);
305
306   tri = g_malloc (padding_before + service_len + path_len + iface_len + 3);
307
308   len = padding_before;
309   
310   if (service)
311     memcpy (&tri[len], service, service_len);
312
313   len += service_len;
314   tri[len] = '\0';
315   len += 1;
316
317   g_assert (len == (padding_before + service_len + 1));
318   
319   memcpy (&tri[len], path, path_len);
320   len += path_len;
321   tri[len] = '\0';
322   len += 1;
323
324   g_assert (len == (padding_before + service_len + path_len + 2));
325   
326   memcpy (&tri[len], interface, iface_len);
327   len += iface_len;
328   tri[len] = '\0';
329   len += 1;
330
331   g_assert (len == (padding_before + service_len + path_len + iface_len + 3));
332
333   return tri;
334 }
335
336 static char*
337 tristring_from_proxy (DBusGProxy *proxy)
338 {
339   return tristring_alloc_from_strings (0,
340                                        proxy->service,
341                                        proxy->path,
342                                        proxy->interface);
343 }
344
345 static char*
346 tristring_from_message (DBusMessage *message)
347 {
348   return tristring_alloc_from_strings (0,
349                                        dbus_message_get_sender (message),
350                                        dbus_message_get_path (message),
351                                        dbus_message_get_interface (message));
352 }
353
354 static DBusGProxyList*
355 gproxy_list_new (DBusGProxy *first_proxy)
356 {
357   DBusGProxyList *list;
358   
359   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
360                                                first_proxy->service,
361                                                first_proxy->path,
362                                                first_proxy->interface);
363   list->proxies = NULL;
364
365   return list;
366 }
367
368 static void
369 gproxy_list_free (DBusGProxyList *list)
370 {
371   /* we don't hold a reference to the proxies in the list,
372    * as they ref the GProxyManager
373    */
374   g_slist_free (list->proxies);  
375
376   g_free (list);
377 }
378
379 static char*
380 gproxy_get_match_rule (DBusGProxy *proxy)
381 {
382   /* FIXME Escaping is required here */
383   
384   if (proxy->service)
385     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
386                             proxy->service, proxy->path, proxy->interface);
387   else
388     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
389                             proxy->path, proxy->interface);
390 }
391
392 static void
393 dbus_gproxy_manager_register (DBusGProxyManager *manager,
394                               DBusGProxy        *proxy)
395 {
396   DBusGProxyList *list;
397
398   LOCK_MANAGER (manager);
399
400   if (manager->proxy_lists == NULL)
401     {
402       list = NULL;
403       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
404                                                     tristring_equal,
405                                                     NULL,
406                                                     (GFreeFunc) gproxy_list_free);
407     }
408   else
409     {
410       char *tri;
411
412       tri = tristring_from_proxy (proxy);
413       
414       list = g_hash_table_lookup (manager->proxy_lists, tri);
415
416       g_free (tri);
417     }
418       
419   if (list == NULL)
420     {
421       list = gproxy_list_new (proxy);
422       
423       g_hash_table_replace (manager->proxy_lists,
424                             list->name, list);
425     }
426
427   if (list->proxies == NULL)
428     {
429       /* We have to add the match rule to the server,
430        * but FIXME only if the server is a message bus,
431        * not if it's a peer.
432        */
433       char *rule;
434
435       rule = gproxy_get_match_rule (proxy);
436       
437       /* We don't check for errors; it's not like anyone would handle them,
438        * and we don't want a round trip here.
439        */
440       dbus_bus_add_match (manager->connection,
441                           rule, NULL);
442
443       g_free (rule);
444     }
445
446   g_assert (g_slist_find (list->proxies, proxy) == NULL);
447   
448   list->proxies = g_slist_prepend (list->proxies, proxy);
449   
450   UNLOCK_MANAGER (manager);
451 }
452
453 static void
454 dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
455                                 DBusGProxy        *proxy)
456 {
457   DBusGProxyList *list;
458   char *tri;
459   
460   LOCK_MANAGER (manager);
461
462 #ifndef G_DISABLE_CHECKS
463   if (manager->proxy_lists == NULL)
464     {
465       g_warning ("Trying to unregister a proxy but there aren't any registered");
466       return;
467     }
468 #endif
469
470   tri = tristring_from_proxy (proxy);
471   
472   list = g_hash_table_lookup (manager->proxy_lists, tri);
473
474 #ifndef G_DISABLE_CHECKS
475   if (list == NULL)
476     {
477       g_warning ("Trying to unregister a proxy but it isn't registered");
478       return;
479     }
480 #endif
481
482   g_assert (g_slist_find (list->proxies, proxy) != NULL);
483   
484   list->proxies = g_slist_remove (list->proxies, proxy);
485
486   g_assert (g_slist_find (list->proxies, proxy) == NULL);
487
488   if (list->proxies == NULL)
489     {
490       g_hash_table_remove (manager->proxy_lists,
491                            tri);
492       list = NULL;
493     }
494   
495   if (g_hash_table_size (manager->proxy_lists) == 0)
496     {
497       g_hash_table_destroy (manager->proxy_lists);
498       manager->proxy_lists = NULL;
499     }
500
501   g_free (tri);
502       
503   UNLOCK_MANAGER (manager);
504 }
505
506 static void
507 list_proxies_foreach (gpointer key,
508                       gpointer value,
509                       gpointer user_data)
510 {
511   DBusGProxyList *list;
512   GSList **ret;
513   GSList *tmp;
514   
515   list = value;
516   ret = user_data;
517
518   tmp = list->proxies;
519   while (tmp != NULL)
520     {
521       DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
522
523       g_object_ref (proxy);
524       *ret = g_slist_prepend (*ret, proxy);
525       
526       tmp = tmp->next;
527     }
528 }
529
530 static GSList*
531 dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
532 {
533   GSList *ret;
534
535   ret = NULL;
536
537   if (manager->proxy_lists)
538     {
539       g_hash_table_foreach (manager->proxy_lists,
540                             list_proxies_foreach,
541                             &ret);
542     }
543
544   return ret;
545 }
546
547 static DBusHandlerResult
548 dbus_gproxy_manager_filter (DBusConnection    *connection,
549                             DBusMessage       *message,
550                             void              *user_data)
551 {
552   DBusGProxyManager *manager;
553   
554   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
555     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
556
557   manager = user_data;
558
559   dbus_gproxy_manager_ref (manager);
560   
561   LOCK_MANAGER (manager);
562   
563   if (dbus_message_is_signal (message,
564                               DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
565                               "Disconnected"))
566     {
567       /* Destroy all the proxies, quite possibly resulting in unreferencing
568        * the proxy manager and the connection as well.
569        */
570       GSList *all;
571       GSList *tmp;
572
573       all = dbus_gproxy_manager_list_all (manager);
574
575       tmp = all;
576       while (tmp != NULL)
577         {
578           DBusGProxy *proxy;
579
580           proxy = DBUS_GPROXY (tmp->data);
581
582           UNLOCK_MANAGER (manager);
583           dbus_gproxy_destroy (proxy);
584           g_object_unref (G_OBJECT (proxy));
585           LOCK_MANAGER (manager);
586           
587           tmp = tmp->next;
588         }
589
590       g_slist_free (all);
591
592 #ifndef G_DISABLE_CHECKS
593       if (manager->proxy_lists != NULL)
594         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.");
595 #endif
596     }
597   else
598     {
599       char *tri;
600       DBusGProxyList *list;
601       
602       tri = tristring_from_message (message);
603
604       if (manager->proxy_lists)
605         list = g_hash_table_lookup (manager->proxy_lists, tri);
606       else
607         list = NULL;
608
609 #if 0
610       g_print ("proxy got %s,%s,%s = list %p\n",
611                tri,
612                tri + strlen (tri) + 1,
613                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
614                list);
615 #endif
616       
617       g_free (tri);
618
619       /* Emit the signal */
620       
621       if (list != NULL)
622         {
623           GSList *tmp;
624           GSList *copy;
625
626           copy = g_slist_copy (list->proxies);
627           g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
628           
629           tmp = copy;
630           while (tmp != NULL)
631             {
632               DBusGProxy *proxy;
633
634               proxy = DBUS_GPROXY (tmp->data);
635
636               UNLOCK_MANAGER (manager);
637               dbus_gproxy_emit_received (proxy, message);
638               g_object_unref (G_OBJECT (proxy));
639               LOCK_MANAGER (manager);
640               
641               tmp = tmp->next;
642             }
643
644           g_slist_free (copy);
645         }
646     }
647
648   UNLOCK_MANAGER (manager);
649   dbus_gproxy_manager_unref (manager);
650   
651   /* "Handling" signals doesn't make sense, they are for everyone
652    * who cares
653    */
654   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
655 }
656
657
658
659 /*      ---------- DBusGProxy --------------   */
660
661
662
663 enum
664 {
665   DESTROY,
666   RECEIVED,
667   LAST_SIGNAL
668 };
669
670 static void *parent_class;
671 static guint signals[LAST_SIGNAL] = { 0 };
672
673 static void
674 dbus_gproxy_init (DBusGProxy *proxy)
675 {
676   /* Nothing */
677 }
678
679 static void
680 dbus_gproxy_class_init (DBusGProxyClass *klass)
681 {
682   GObjectClass *object_class = G_OBJECT_CLASS (klass);
683   
684   parent_class = g_type_class_peek_parent (klass);
685   
686   object_class->finalize = dbus_gproxy_finalize;
687   object_class->dispose = dbus_gproxy_dispose;
688   
689   signals[DESTROY] =
690     g_signal_new ("destroy",
691                   G_OBJECT_CLASS_TYPE (object_class),
692                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
693                   0,
694                   NULL, NULL,
695                   g_cclosure_marshal_VOID__VOID,
696                   G_TYPE_NONE, 0);
697   
698   signals[RECEIVED] =
699     g_signal_new ("received",
700                   G_OBJECT_CLASS_TYPE (object_class),
701                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
702                   0,
703                   NULL, NULL,
704                   g_cclosure_marshal_VOID__BOXED,
705                   G_TYPE_NONE, 1,
706                   DBUS_TYPE_MESSAGE);
707 }
708
709
710 static void
711 dbus_gproxy_dispose (GObject *object)
712 {
713   DBusGProxy *proxy;
714
715   proxy = DBUS_GPROXY (object);
716
717   g_signal_emit (object, signals[DESTROY], 0);
718   
719   G_OBJECT_CLASS (parent_class)->dispose (object);
720 }
721
722 static void
723 dbus_gproxy_finalize (GObject *object)
724 {
725   DBusGProxy *proxy;
726
727   proxy = DBUS_GPROXY (object);
728
729   if (proxy->manager)
730     {
731       dbus_gproxy_manager_unregister (proxy->manager, proxy);
732       dbus_gproxy_manager_unref (proxy->manager);
733     }
734   
735   g_free (proxy->service);
736   g_free (proxy->path);
737   g_free (proxy->interface);
738   
739   G_OBJECT_CLASS (parent_class)->finalize (object);
740 }
741
742 static void
743 dbus_gproxy_destroy (DBusGProxy *proxy)
744 {
745   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
746    * from GtkObject?
747    */
748   g_object_run_dispose (G_OBJECT (proxy));
749 }
750
751 static char*
752 create_signal_detail (const char *interface,
753                       const char *signal)
754 {
755   GString *str;
756
757   str = g_string_new (interface);
758
759   g_string_append (str, ".");
760
761   g_string_append (str, signal);
762
763   return g_string_free (str, FALSE);
764 }
765
766 static void
767 dbus_gproxy_emit_received (DBusGProxy  *proxy,
768                            DBusMessage *message)
769 {
770   const char *interface;
771   const char *signal;
772   char *detail;
773   GQuark q;
774   
775   interface = dbus_message_get_interface (message);
776   signal = dbus_message_get_member (message);
777
778   g_assert (interface != NULL);
779   g_assert (signal != NULL);
780
781   detail = create_signal_detail (interface, signal);
782
783   /* If the quark isn't preexisting, there's no way there
784    * are any handlers connected. We don't want to create
785    * extra quarks for every possible signal.
786    */
787   q = g_quark_try_string (detail);
788
789   if (q != 0)
790     g_signal_emit (G_OBJECT (proxy),
791                    signals[RECEIVED],
792                    q,
793                    message);
794
795   g_free (detail);
796 }
797
798 /** @} End of DBusGLibInternals */
799
800 /** @addtogroup DBusGLib
801  * @{
802  */
803
804 /**
805  * Standard GObject get_type() function for DBusGProxy.
806  *
807  * @returns type ID for DBusGProxy class
808  */
809 GType
810 dbus_gproxy_get_type (void)
811 {
812   static GType object_type = 0;
813
814   if (!object_type)
815     {
816       static const GTypeInfo object_info =
817         {
818           sizeof (DBusGProxyClass),
819           (GBaseInitFunc) NULL,
820           (GBaseFinalizeFunc) NULL,
821           (GClassInitFunc) dbus_gproxy_class_init,
822           NULL,           /* class_finalize */
823           NULL,           /* class_data */
824           sizeof (DBusGProxy),
825           0,              /* n_preallocs */
826           (GInstanceInitFunc) dbus_gproxy_init,
827         };
828       
829       object_type = g_type_register_static (G_TYPE_OBJECT,
830                                             "DBusGProxy",
831                                             &object_info, 0);
832     }
833   
834   return object_type;
835 }
836
837 static DBusGProxy*
838 dbus_gproxy_new (DBusConnection *connection,
839                  const char     *service_name,
840                  const char     *path_name,
841                  const char     *interface_name)
842 {
843   DBusGProxy *proxy;
844
845   g_assert (connection != NULL);
846   
847   proxy = g_object_new (DBUS_TYPE_GPROXY, NULL);
848
849   /* These should all be construct-only mandatory properties,
850    * for now we just don't let people use g_object_new().
851    */
852   
853   proxy->manager = dbus_gproxy_manager_get (connection);
854   
855   proxy->service = g_strdup (service_name);
856   proxy->path = g_strdup (path_name);
857   proxy->interface = g_strdup (interface_name);
858
859   dbus_gproxy_manager_register (proxy->manager, proxy);
860   
861   return proxy;
862 }
863
864 /**
865  * Creates a new proxy for a remote interface exported by a service on
866  * a message bus. Method calls and signal connections over this proxy
867  * will go to the service owner; the service owner is expected to
868  * support the given interface name. THE SERVICE OWNER MAY CHANGE OVER
869  * TIME, for example between two different method calls. If you need a
870  * fixed owner, you need to request the current owner and bind a proxy
871  * to that rather than to the generic service name; see
872  * dbus_gproxy_new_for_service_owner().
873  *
874  * A service-associated proxy only makes sense with a message bus,
875  * not for app-to-app direct dbus connections.
876  *
877  * This proxy will only emit the "destroy" signal if the #DBusConnection
878  * is disconnected or the proxy is has no remaining references.
879  *
880  * @param connection the connection to the remote bus
881  * @param service_name name of the service on the message bus
882  * @param path_name name of the object inside the service to call methods on
883  * @param interface_name name of the interface to call methods on
884  * @returns new proxy object
885  */
886 DBusGProxy*
887 dbus_gproxy_new_for_service (DBusConnection *connection,
888                              const char     *service_name,
889                              const char     *path_name,
890                              const char     *interface_name)
891 {
892   DBusGProxy *proxy;
893
894   g_return_val_if_fail (connection != NULL, NULL);
895   g_return_val_if_fail (service_name != NULL, NULL);
896   g_return_val_if_fail (path_name != NULL, NULL);
897   g_return_val_if_fail (interface_name != NULL, NULL);
898   
899   proxy = dbus_gproxy_new (connection, service_name,
900                            path_name, interface_name);
901
902   return proxy;
903 }
904
905 /**
906  * Similar to dbus_gproxy_new_for_service(), but makes a round-trip
907  * request to the message bus to get the current service owner, then
908  * binds the proxy specifically to the current owner. As a result, the
909  * service owner will not change over time, and the proxy will emit
910  * the "destroy" signal when the owner disappears from the message
911  * bus.
912  *
913  * An example of the difference between dbus_gproxy_new_for_service()
914  * and dbus_gproxy_new_for_service_owner(): if you pass the service name
915  * "org.freedesktop.Database" dbus_gproxy_new_for_service() remains bound
916  * to that name as it changes owner. dbus_gproxy_new_for_service_owner()
917  * will fail if the service has no owner. If the service has an owner,
918  * dbus_gproxy_new_for_service_owner() will bind to the unique name
919  * of that owner rather than the generic service name.
920  * 
921  * @param connection the connection to the remote bus
922  * @param service_name name of the service on the message bus
923  * @param path_name name of the object inside the service to call methods on
924  * @param interface_name name of the interface to call methods on
925  * @param error return location for an error
926  * @returns new proxy object, or #NULL on error
927  */
928 DBusGProxy*
929 dbus_gproxy_new_for_service_owner (DBusConnection           *connection,
930                                    const char               *service_name,
931                                    const char               *path_name,
932                                    const char               *interface_name,
933                                    GError                  **error)
934 {
935   g_return_val_if_fail (connection != NULL, NULL);
936   g_return_val_if_fail (service_name != NULL, NULL);
937   g_return_val_if_fail (path_name != NULL, NULL);
938   g_return_val_if_fail (interface_name != NULL, NULL);
939
940
941 }
942
943 /**
944  * Creates a proxy for an object in peer application (one
945  * we're directly connected to). That is, this function is
946  * intended for use when there's no message bus involved,
947  * we're doing a simple 1-to-1 communication between two
948  * applications.
949  *
950  *
951  * @param connection the connection to the peer
952  * @param path_name name of the object inside the peer to call methods on
953  * @param interface_name name of the interface to call methods on
954  * @returns new proxy object
955  * 
956  */
957 DBusGProxy*
958 dbus_gproxy_new_for_peer (DBusConnection           *connection,
959                           const char               *path_name,
960                           const char               *interface_name)
961 {
962   DBusGProxy *proxy;
963   
964   g_return_val_if_fail (connection != NULL, NULL);
965   g_return_val_if_fail (path_name != NULL, NULL);
966   g_return_val_if_fail (interface_name != NULL, NULL);
967
968   proxy = dbus_gproxy_new (connection, NULL,
969                            path_name, interface_name);
970
971   return proxy;
972 }
973
974 /**
975  * Invokes a method on a remote interface. This function does not
976  * block; instead it returns an opaque #DBusPendingCall object that
977  * tracks the pending call.  The method call will not be sent over the
978  * wire until the application returns to the main loop, or blocks in
979  * dbus_connection_flush() to write out pending data.  The call will
980  * be completed after a timeout, or when a reply is received.
981  * To collect the results of the call (which may be an error,
982  * or a reply), use dbus_gproxy_end_call().
983  *
984  * @todo this particular function shouldn't die on out of memory,
985  * since you should be able to do a call with large arguments.
986  * 
987  * @param proxy a proxy for a remote interface
988  * @param method the name of the method to invoke
989  * @param first_arg_type type of the first argument
990  *
991  * @returns opaque pending call object
992  *  */
993 DBusPendingCall*
994 dbus_gproxy_begin_call (DBusGProxy *proxy,
995                         const char *method,
996                         int         first_arg_type,
997                         ...)
998 {
999   DBusPendingCall *pending;
1000   DBusMessage *message;
1001   va_list args;
1002   
1003   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL);
1004
1005   message = dbus_message_new_method_call (proxy->service,
1006                                           proxy->path,
1007                                           proxy->interface,
1008                                           method);
1009   if (message == NULL)
1010     goto oom;
1011
1012   va_start (args, first_arg_type);
1013   if (!dbus_message_append_args_valist (message, first_arg_type,
1014                                         args))
1015     goto oom;
1016   va_end (args);
1017
1018   if (!dbus_connection_send_with_reply (proxy->manager->connection,
1019                                         message,
1020                                         &pending,
1021                                         -1))
1022     goto oom;
1023
1024   return pending;
1025
1026  oom:
1027   /* FIXME we should create a pending call that's
1028    * immediately completed with an error status without
1029    * ever going on the wire.
1030    */
1031   
1032   g_error ("Out of memory");
1033   return NULL;
1034 }
1035
1036 /**
1037  * Collects the results of a method call. The method call was normally
1038  * initiated with dbus_gproxy_end_call(). This function will block if
1039  * the results haven't yet been received; use
1040  * dbus_pending_call_set_notify() to be notified asynchronously that a
1041  * pending call has been completed. Use
1042  * dbus_pending_call_get_completed() to check whether a call has been
1043  * completed. If it's completed, it will not block.
1044  *
1045  * If the call results in an error, the error is set as normal for
1046  * GError and the function returns #FALSE.
1047  *
1048  * Otherwise, the "out" parameters and return value of the
1049  * method are stored in the provided varargs list.
1050  * The list should be terminated with DBUS_TYPE_INVALID.
1051  *
1052  * This function doesn't affect the reference count of the
1053  * #DBusPendingCall, the caller of dbus_gproxy_begin_call() still owns
1054  * a reference.
1055  *
1056  * @param proxy a proxy for a remote interface
1057  * @param pending the pending call from dbus_gproxy_begin_call()
1058  * @param error return location for an error
1059  * @param first_arg_type type of first "out" argument
1060  * @returns #FALSE if an error is set */
1061 gboolean
1062 dbus_gproxy_end_call (DBusGProxy          *proxy,
1063                       DBusPendingCall     *pending,
1064                       GError             **error,
1065                       int                  first_arg_type,
1066                       ...)
1067 {
1068   DBusMessage *message;
1069   va_list args;
1070   DBusError derror;
1071   
1072   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE);
1073   g_return_val_if_fail (pending != NULL, FALSE);
1074
1075   dbus_pending_call_block (pending);
1076   message = dbus_pending_call_get_reply (pending);
1077
1078   g_assert (message != NULL);
1079
1080   dbus_error_init (&derror);
1081
1082   switch (dbus_message_get_type (message))
1083     {
1084     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
1085       va_start (args, first_arg_type);
1086       if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
1087         {
1088           va_end (args);
1089           goto error;
1090         }
1091       va_end (args);
1092
1093       return TRUE;
1094       
1095     case DBUS_MESSAGE_TYPE_ERROR:
1096       dbus_set_error_from_message (&derror, message);
1097       goto error;
1098
1099     default:
1100       dbus_set_error (&derror, DBUS_ERROR_FAILED,
1101                       "Reply was neither a method return nor an exception");
1102       goto error;
1103     }
1104
1105  error:
1106   dbus_set_g_error (error, &derror);
1107   dbus_error_free (&derror);
1108   return FALSE;
1109 }
1110
1111 /**
1112  * Sends a method call message as with dbus_gproxy_begin_call(), but
1113  * does not ask for a reply or allow you to receive one.
1114  *
1115  * @todo this particular function shouldn't die on out of memory,
1116  * since you should be able to do a call with large arguments.
1117  * 
1118  * @param proxy a proxy for a remote interface
1119  * @param method the name of the method to invoke
1120  * @param first_arg_type type of the first argument
1121  */
1122 void
1123 dbus_gproxy_call_no_reply (DBusGProxy               *proxy,
1124                            const char               *method,
1125                            int                       first_arg_type,
1126                            ...)
1127 {
1128   DBusMessage *message;
1129   va_list args;
1130   
1131   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1132
1133   message = dbus_message_new_method_call (proxy->service,
1134                                           proxy->path,
1135                                           proxy->interface,
1136                                           method);
1137   if (message == NULL)
1138     goto oom;
1139
1140   dbus_message_set_no_reply (message, TRUE);
1141   
1142   va_start (args, first_arg_type);
1143   if (!dbus_message_append_args_valist (message, first_arg_type,
1144                                         args))
1145     goto oom;
1146   va_end (args);
1147
1148   if (!dbus_connection_send (proxy->manager->connection,
1149                              message,
1150                              NULL))
1151     goto oom;
1152
1153   return;
1154   
1155  oom:
1156   g_error ("Out of memory");
1157 }
1158
1159 /**
1160  * Sends a message to the interface we're proxying for.  Does not
1161  * block or wait for a reply. The message is only actually written out
1162  * when you return to the main loop or block in
1163  * dbus_connection_flush().
1164  *
1165  * The message is modified to be addressed to the target interface.
1166  * That is, a destination service field or whatever is needed will be
1167  * added to the message. The basic point of this function is to add
1168  * the necessary header fields, otherwise it's equivalent to
1169  * dbus_connection_send().
1170  *
1171  * This function adds a reference to the message, so the caller
1172  * still owns its original reference.
1173  * 
1174  * @param proxy a proxy for a remote interface
1175  * @param message the message to address and send
1176  * @param client_serial return location for message's serial, or #NULL */
1177 void
1178 dbus_gproxy_send (DBusGProxy          *proxy,
1179                   DBusMessage         *message,
1180                   dbus_uint32_t       *client_serial)
1181 {
1182   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1183   
1184   if (proxy->service)
1185     {
1186       if (!dbus_message_set_destination (message, proxy->service))
1187         g_error ("Out of memory");
1188     }
1189   if (proxy->path)
1190     {
1191       if (!dbus_message_set_path (message, proxy->path))
1192         g_error ("Out of memory");
1193     }
1194   if (proxy->interface)
1195     {
1196       if (!dbus_message_set_interface (message, proxy->interface))
1197         g_error ("Out of memory");
1198     }
1199   
1200   if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
1201     g_error ("Out of memory\n");
1202 }
1203
1204 void
1205 dbus_gproxy_connect_signal (DBusGProxy             *proxy,
1206                             const char             *signal_name,
1207                             DBusGProxySignalHandler handler,
1208                             void                   *data,
1209                             GClosureNotify          free_data_func)
1210 {
1211   GClosure *closure;
1212   char *detail;
1213
1214   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1215   g_return_if_fail (signal_name != NULL);
1216   g_return_if_fail (handler != NULL);
1217   
1218   detail = create_signal_detail (proxy->interface, signal_name);
1219   
1220   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
1221   g_signal_connect_closure_by_id (G_OBJECT (proxy),
1222                                   signals[RECEIVED],
1223                                   g_quark_from_string (detail),
1224                                   closure, FALSE);
1225
1226   g_free (detail);
1227 }
1228
1229 void
1230 dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,
1231                                const char             *signal_name,
1232                                DBusGProxySignalHandler handler,
1233                                void                   *data)
1234 {
1235   char *detail;
1236   GQuark q;
1237   
1238   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1239   g_return_if_fail (signal_name != NULL);
1240   g_return_if_fail (handler != NULL);
1241
1242   detail = create_signal_detail (proxy->interface, signal_name);
1243   q = g_quark_try_string (detail);
1244   g_free (detail);
1245
1246 #ifndef G_DISABLE_CHECKS
1247   if (q == 0)
1248     {
1249       g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
1250                  G_GNUC_FUNCTION, signal_name);
1251       return;
1252     }
1253 #endif
1254
1255   g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
1256                                         G_SIGNAL_MATCH_DETAIL |
1257                                         G_SIGNAL_MATCH_FUNC   |
1258                                         G_SIGNAL_MATCH_DATA,
1259                                         signals[RECEIVED],
1260                                         q,
1261                                         NULL,
1262                                         G_CALLBACK (handler), data);
1263 }
1264
1265 /** @} End of DBusGLib public */
1266
1267 #ifdef DBUS_BUILD_TESTS
1268
1269 /**
1270  * @ingroup DBusGLibInternals
1271  * Unit test for GLib proxy functions
1272  * @returns #TRUE on success.
1273  */
1274 dbus_bool_t
1275 _dbus_gproxy_test (void)
1276 {
1277   
1278   
1279   return TRUE;
1280 }
1281
1282 #endif /* DBUS_BUILD_TESTS */