migration from private to rsa
[external/dbus-glib.git] / dbus / dbus-gobject.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gobject.c Exporting a GObject remotely
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 #include <gobject/gvaluecollector.h>
27 #include <dbus/dbus-glib.h>
28 #include <dbus/dbus-glib-lowlevel.h>
29 #include "dbus-gtest.h"
30 #include "dbus-gutils.h"
31 #include "dbus-gobject.h"
32 #include "dbus-gsignature.h"
33 #include "dbus-gvalue.h"
34 #include "dbus-gmarshal.h"
35 #include "dbus-gvalue-utils.h"
36 #include <string.h>
37
38 #include <gio/gio.h>
39
40 G_GNUC_NORETURN static void
41 oom (const gchar *explanation)
42 {
43   g_error ("%s", explanation == NULL ? "Out of memory" : explanation);
44   g_assert_not_reached ();
45 }
46
47 static DBusMessage *
48 reply_or_die (DBusMessage *in_reply_to)
49 {
50   DBusMessage *reply;
51
52   g_return_val_if_fail (in_reply_to != NULL, NULL);
53
54   reply = dbus_message_new_method_return (in_reply_to);
55
56   if (reply == NULL)
57     oom ("dbus_message_new_method_return failed: out of memory?");
58
59   return reply;
60 }
61
62 static DBusMessage *
63 error_or_die (DBusMessage *in_reply_to,
64     const gchar *error_name,
65     const gchar *error_message)
66 {
67   DBusMessage *reply;
68
69   g_return_val_if_fail (in_reply_to != NULL, NULL);
70   /* error names are syntactically the same as interface names */
71   g_return_val_if_fail (g_dbus_is_interface_name (error_name), NULL);
72   g_return_val_if_fail (g_utf8_validate (error_message, -1, NULL), NULL);
73
74   reply = dbus_message_new_error (in_reply_to, error_name, error_message);
75
76   if (reply == NULL)
77     oom ("dbus_message_new_error failed: out of memory?");
78
79   return reply;
80 }
81
82 static void
83 connection_send_or_die (DBusConnection *connection,
84     DBusMessage *message)
85 {
86   g_return_if_fail (connection != NULL);
87   g_return_if_fail (message != NULL);
88
89   if (!dbus_connection_send (connection, message, NULL))
90     oom ("dbus_connection_send failed: out of memory?");
91 }
92
93 static char *lookup_property_name (GObject    *object,
94                                    const char *wincaps_propiface,
95                                    const char *requested_propname);
96
97 typedef struct
98 {
99   char *default_iface;
100   GType code_enum;
101 } DBusGErrorInfo;
102
103 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
104 /* See comments in check_property_access */
105 static gboolean disable_legacy_property_access = FALSE;
106 static GHashTable *marshal_table = NULL;
107 static GData *error_metadata = NULL;
108
109 static char*
110 uscore_to_wincaps_full (const char *uscore,
111                         gboolean    uppercase_first,
112                         gboolean    strip_underscores)
113 {
114   const char *p;
115   GString *str;
116   gboolean last_was_uscore;
117
118   last_was_uscore = uppercase_first;
119   
120   str = g_string_new (NULL);
121   p = uscore;
122   while (p && *p)
123     {
124       if (*p == '-' || (strip_underscores && *p == '_'))
125         {
126           last_was_uscore = TRUE;
127         }
128       else
129         {
130           if (last_was_uscore)
131             {
132               g_string_append_c (str, g_ascii_toupper (*p));
133               last_was_uscore = FALSE;
134             }
135           else
136             g_string_append_c (str, *p);
137         }
138       ++p;
139     }
140
141   return g_string_free (str, FALSE);
142 }
143
144 /* Ugly yes - but we have to accept strings from both formats */
145 static gboolean
146 compare_strings_ignoring_uscore_vs_dash (const char *a, const char *b)
147 {
148   guint i;
149
150   for (i = 0; a[i] && b[i]; i++)
151     {
152       if ((a[i] == '-' && b[i] == '_')
153           || (a[i] == '_' && b[i] == '-'))
154         continue;
155       if (a[i] != b[i])
156         return FALSE;
157     }
158   return (a[i] == '\0') && (b[i] == '\0');
159 }
160
161 static char *
162 uscore_to_wincaps (const char *uscore)
163 {
164   return uscore_to_wincaps_full (uscore, TRUE, TRUE);
165 }
166
167 static const char *
168 string_table_next (const char *table)
169 {
170   return (table + (strlen (table) + 1));
171 }
172
173 static const char *
174 string_table_lookup (const char *table, int index)
175 {
176   const char *ret;
177
178   ret = table;
179
180   while (index--)
181     ret = string_table_next (ret);
182
183   return ret;
184 }
185
186 static const char *
187 get_method_data (const DBusGObjectInfo *object,
188                  const DBusGMethodInfo *method)
189 {
190   return object->data + method->data_offset;
191 }
192
193 static char *
194 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
195 {
196   /* FIXME */
197   return NULL;
198 }
199
200 static char *
201 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
202 {
203   /* FIXME */
204   return NULL;
205 }
206
207 static const char *
208 method_interface_from_object_info (const DBusGObjectInfo *object,
209                               const DBusGMethodInfo *method)
210 {
211   return string_table_lookup (get_method_data (object, method), 0);
212 }
213
214 static const char *
215 method_name_from_object_info (const DBusGObjectInfo *object,
216                               const DBusGMethodInfo *method)
217 {
218   return string_table_lookup (get_method_data (object, method), 1);
219 }
220
221 static const char *
222 method_arg_info_from_object_info (const DBusGObjectInfo *object,
223                                   const DBusGMethodInfo *method)
224 {
225   return string_table_lookup (get_method_data (object, method), 3);/*RB was 2*/
226 }
227
228 typedef enum
229 {
230   RETVAL_NONE,    
231   RETVAL_NOERROR,    
232   RETVAL_ERROR
233 } RetvalType;
234
235 /*
236  * arg_iterate:
237  * @data: a pointer to the beginning of an argument entry in a string table
238  * @name: (out) (allow-none): used to return the name of the next argument
239  * @in: (out) (allow-none): used to return %TRUE for an "in" argument or
240  *    %FALSE for an "out" argument
241  * @constval: (out) (allow-none): used to return %TRUE if the argument is
242  *    an "out" argument and has the "C" (const) flag indicating that it
243  *    should not be freed after it is returned; normally, "out" arguments
244  *    are freed
245  * @retval: (out) (allow-none): used to return %RETVAL_NONE if this
246  *    D-Bus argument is not an "out" argument or is obtained like a C "out"
247  *    parameter, %RETVAL_ERROR if this argument is obtained from the C
248  *    return value and is also used to signal errors, or %RETVAL_NOERROR
249  *    if this argument is obtained from the C return value and the method
250  *    can never raise an error
251  * @type: (out) (allow-none): used to return the D-Bus signature of this
252  *    argument
253  *
254  * The data format is:
255  *
256  * argument name
257  * \0
258  * direction: I or O
259  * \0
260  * if direction == "O":
261  *     freeable? F or C
262  *     \0
263  *     retval? N, E or R
264  *     \0
265  * signature
266  * \0
267  *
268  * If none of the arguments has @retval != %RETVAL_NONE, the method is
269  * assumed to return a gboolean, which behaves like %RETVAL_ERROR but is
270  * not sent over D-Bus at all.
271  *
272  * Returns: the value of @data to use for the next call, or a pointer to '\0'
273  *    if this function must not be called again
274  */
275 static const char *
276 arg_iterate (const char    *data,
277              const char   **name,
278              gboolean      *in,
279              gboolean      *constval,
280              RetvalType    *retval,
281              const char   **type)
282 {
283   gboolean inarg;
284
285   if (name)
286     *name = data;
287
288   data = string_table_next (data);
289   switch (*data)
290     {
291     case 'I':
292       inarg = TRUE;
293       break;
294     case 'O':
295       inarg = FALSE;
296       break;
297     default:
298       g_warning ("invalid arg direction '%c'", *data);
299       inarg = FALSE;
300       break;
301     }
302   if (in)
303     *in = inarg;
304
305   if (!inarg)
306     {
307       data = string_table_next (data);
308       switch (*data)
309         {
310         case 'F':
311           if (constval)
312             *constval = FALSE;
313           break;
314         case 'C':
315           if (constval)
316             *constval = TRUE;
317           break;
318         default:
319           g_warning ("invalid arg const value '%c'", *data);
320           break;
321         }
322       data = string_table_next (data);
323       switch (*data)
324         {
325         case 'N':
326           if (retval)
327             *retval = RETVAL_NONE;
328           break;
329         case 'E':
330           if (retval)
331             *retval = RETVAL_ERROR;
332           break;
333         case 'R':
334           if (retval)
335             *retval = RETVAL_NOERROR;
336           break;
337         default:
338           g_warning ("invalid arg ret value '%c'", *data);
339           break;
340         }
341     }
342   else
343     {
344       if (constval)
345         *constval = FALSE;
346       if (retval)
347         *retval = FALSE;
348     }
349   
350   data = string_table_next (data);
351   if (type)
352     *type = data;
353
354   return string_table_next (data);
355 }
356
357 static char *
358 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
359                                        const DBusGMethodInfo *method,
360                                        gboolean               in)
361 {
362   const char *arg;
363   GString *ret;
364
365   arg = method_arg_info_from_object_info (object, method);
366
367   ret = g_string_new (NULL);
368
369   while (*arg)
370     {
371       const char *name;
372       gboolean arg_in;
373       const char *type;
374
375       arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
376
377       if (arg_in == in)
378         g_string_append (ret, type);
379     }
380
381   return g_string_free (ret, FALSE);
382 }
383
384 static char *
385 method_input_signature_from_object_info (const DBusGObjectInfo *object,
386                                          const DBusGMethodInfo *method)
387 {
388   return method_dir_signature_from_object_info (object, method, TRUE);
389 }
390
391 static char *
392 method_output_signature_from_object_info (const DBusGObjectInfo *object,
393                                           const DBusGMethodInfo *method)
394 {
395   return method_dir_signature_from_object_info (object, method, FALSE);
396 }
397
398 static const char *
399 signal_iterate (const char *data, const char **iface, const char **name)
400 {
401   *iface = data;
402
403   data = string_table_next (data);
404   *name = data;
405
406   return string_table_next (data);
407 }
408
409 static const char *
410 property_iterate (const char  *data,
411                   int          format_version,
412                   const char **iface,
413                   const char **exported_name,
414                   const char **name_uscored,
415                   const char **access_type)
416 {
417   *iface = data;
418
419   data = string_table_next (data);
420   *exported_name = data;
421
422   data = string_table_next (data);
423   if (format_version == 1)
424     {
425       *name_uscored = data;
426       data = string_table_next (data);
427       *access_type = data;
428       return string_table_next (data);
429     }
430   else
431     {
432       /* This tells the caller they need to compute it */
433       *name_uscored = NULL;
434       /* We don't know here, however note that we will still check against the
435        * readable/writable flags from GObject's metadata.
436        */
437       *access_type = "readwrite";
438       return data;
439     }
440 }
441
442 /**
443  * property_info_from_object_info:
444  * @object: introspection data
445  * @interface_name: (allow-none): Expected interface name, or %NULL for any
446  * @property_name: Expected property name (can use "-" or "_" as separator)
447  * @access_type: (out): Can be one of "read", "write", "readwrite"
448  *
449  * Look up property introspection data for the given interface/name pair.
450  *
451  * Returns: %TRUE if property was found
452  */
453 static gboolean
454 property_info_from_object_info (const DBusGObjectInfo  *object,
455                                 const char             *interface_name,
456                                 const char             *property_name,
457                                 const char            **access_type)
458 {
459   const char *properties_iter;
460
461   properties_iter = object->exported_properties;
462   while (properties_iter != NULL && *properties_iter)
463     {
464       const char *cur_interface_name;
465       const char *cur_property_name;
466       const char *cur_uscore_property_name;
467       const char *cur_access_type;
468
469
470       properties_iter = property_iterate (properties_iter, object->format_version,
471                                           &cur_interface_name, &cur_property_name,
472                                           &cur_uscore_property_name, &cur_access_type);
473
474       if (interface_name && strcmp (interface_name, cur_interface_name) != 0)
475         continue;
476
477       /* This big pile of ugly is necessary to support the matrix resulting from multiplying
478        * (v0 data, v1 data) * (FooBar, foo-bar)
479        * In v1 data we have both forms of string, so we do a comparison against both without
480        * having to malloc.
481        * For v0 data, we need to reconstruct the foo-bar form.
482        *
483        * Adding to the complexity is that we *also* have to ignore the distinction between
484        * '-' and '_', because g_object_{get,set} does.
485        */
486       /* First, compare against the primary property name - no malloc required */
487       if (!compare_strings_ignoring_uscore_vs_dash (property_name, cur_property_name))
488         {
489           if (cur_uscore_property_name != NULL
490               && !compare_strings_ignoring_uscore_vs_dash (property_name, cur_uscore_property_name))
491             continue;
492           else
493             {
494               /* v0 metadata, construct uscore */
495               char *tmp_uscored;
496               gboolean matches;
497               tmp_uscored = _dbus_gutils_wincaps_to_uscore (cur_property_name);
498               matches = compare_strings_ignoring_uscore_vs_dash (property_name, tmp_uscored);
499               g_free (tmp_uscored);
500               if (!matches)
501                 continue;
502             }
503         }
504
505       *access_type = cur_access_type;
506       return TRUE;
507     }
508   return FALSE;
509 }
510
511 static GQuark
512 dbus_g_object_type_dbus_metadata_quark (void)
513 {
514   static GQuark quark;
515
516   if (!quark)
517     quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
518   return quark;
519 }
520
521 /* Iterator function should return FALSE to stop iteration, TRUE to continue */
522 typedef gboolean (*ForeachObjectInfoFn) (const DBusGObjectInfo *info,
523                                          GType                 gtype,
524                                          gpointer              user_data);
525
526 static void
527 foreach_object_info (GObject *object,
528                      ForeachObjectInfoFn callback,
529                      gpointer user_data)
530 {
531   GType *interfaces, *p;
532   const DBusGObjectInfo *info;
533   GType classtype;
534
535   interfaces = g_type_interfaces (G_TYPE_FROM_INSTANCE (object), NULL);
536
537   for (p = interfaces; *p != 0; p++)
538     {
539       info = g_type_get_qdata (*p, dbus_g_object_type_dbus_metadata_quark ());
540       if (info != NULL && info->format_version >= 0)
541         {
542           if (!callback (info, *p, user_data))
543             break;
544         }
545     }
546
547   g_free (interfaces);
548
549   for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
550     {
551       info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ());
552       if (info != NULL && info->format_version >= 0)
553         {
554           if (!callback (info, classtype, user_data))
555             break;
556         }
557     }
558
559 }
560
561 static gboolean
562 lookup_object_info_cb (const DBusGObjectInfo *info,
563                        GType gtype,
564                        gpointer user_data)
565 {
566   GList **list = (GList **) user_data;
567
568   *list = g_list_prepend (*list, (gpointer) info);
569   return TRUE;
570 }
571
572 static GList *
573 lookup_object_info (GObject *object)
574 {
575   GList *info_list = NULL;
576
577   foreach_object_info (object, lookup_object_info_cb, &info_list);
578
579   return info_list;
580 }
581
582 typedef struct {
583   const char *iface;
584   const DBusGObjectInfo *info;
585   gboolean fallback;
586   GType iface_type;
587 } LookupObjectInfoByIfaceData;
588
589 static gboolean
590 lookup_object_info_by_iface_cb (const DBusGObjectInfo *info,
591                                 GType gtype,
592                                 gpointer user_data)
593 {
594   LookupObjectInfoByIfaceData *lookup_data = (LookupObjectInfoByIfaceData *) user_data;
595
596   /* If interface is not specified, choose the first info */
597   if (lookup_data->fallback && (!lookup_data->iface || strlen (lookup_data->iface) == 0))
598     {
599       lookup_data->info = info;
600       lookup_data->iface_type = gtype;
601     }
602   else if (info->exported_properties && !strcmp (info->exported_properties, lookup_data->iface))
603     {
604       lookup_data->info = info;
605       lookup_data->iface_type = gtype;
606     }
607
608   return !lookup_data->info;
609 }
610
611 static const DBusGObjectInfo *
612 lookup_object_info_by_iface (GObject     *object,
613                              const char  *iface,
614                              gboolean     fallback,
615                              GType       *out_iface_type)
616 {
617   LookupObjectInfoByIfaceData data;
618
619   data.iface = iface;
620   data.info = NULL;
621   data.fallback = fallback;
622   data.iface_type = 0;
623
624   foreach_object_info (object, lookup_object_info_by_iface_cb, &data);
625
626   if (out_iface_type && data.info)
627     *out_iface_type = data.iface_type;
628
629   return data.info;
630 }
631
632 typedef struct {
633     /* owned */
634     GSList *registrations;
635     /* weak ref, or NULL if the object has been disposed */
636     GObject *object;
637 } ObjectExport;
638
639 typedef struct {
640     /* pseudo-weak ref, never NULL */
641     DBusGConnection *connection;
642     /* owned, never NULL */
643     gchar *object_path;
644     /* borrowed pointer to parent, never NULL */
645     ObjectExport *export;
646 } ObjectRegistration;
647
648 static void object_export_object_died (gpointer user_data, GObject *dead);
649
650 static void
651 object_export_unregister_all (ObjectExport *oe)
652 {
653   while (oe->registrations != NULL)
654     {
655       GSList *old = oe->registrations;
656       ObjectRegistration *o = oe->registrations->data;
657
658       dbus_connection_unregister_object_path (
659           DBUS_CONNECTION_FROM_G_CONNECTION (o->connection), o->object_path);
660
661       /* the link should have been removed by doing that */
662       g_assert (oe->registrations != old);
663     }
664 }
665
666 static void
667 object_export_free (ObjectExport *oe)
668 {
669   g_slice_free (ObjectExport, oe);
670 }
671
672 static ObjectExport *
673 object_export_new (void)
674 {
675   return g_slice_new0 (ObjectExport);
676 }
677
678 static ObjectRegistration *
679 object_registration_new (DBusGConnection *connection,
680                          const gchar *object_path,
681                          ObjectExport *export)
682 {
683   ObjectRegistration *o = g_slice_new0 (ObjectRegistration);
684
685   o->connection = connection;
686   o->object_path = g_strdup (object_path);
687   o->export = export;
688
689   return o;
690 }
691
692 static void
693 object_registration_free (ObjectRegistration *o)
694 {
695   g_assert (o->export != NULL);
696   o->export->registrations = g_slist_remove (o->export->registrations, o);
697
698   g_free (o->object_path);
699
700   g_slice_free (ObjectRegistration, o);
701 }
702
703 /* Called when the object falls off the bus (e.g. because connection just
704  * closed) */
705 static void
706 object_registration_unregistered (DBusConnection *connection,
707                                   void *user_data)
708 {
709   object_registration_free (user_data);
710 }
711
712 typedef struct
713 {
714   GObject *object;
715   GString *xml;
716   GType gtype;
717   const DBusGObjectInfo *object_info;
718 } DBusGLibWriteIterfaceData;
719
720 typedef struct
721 {
722   GSList *methods;
723   GSList *signals;
724   GSList *properties;
725 } DBusGLibWriteInterfaceValues;
726
727 static void
728 write_interface (gpointer key, gpointer val, gpointer user_data)
729 {
730   const char *name;
731   GSList *methods;
732   GSList *signals;
733   GSList *properties;
734   GString *xml;
735   const DBusGObjectInfo *object_info;
736   DBusGLibWriteIterfaceData *data;
737   DBusGLibWriteInterfaceValues *values;
738
739   name = key;
740
741   values = val;
742   methods = values->methods;
743   signals = values->signals;
744   properties = values->properties;
745
746   data = user_data;
747   xml = data->xml;
748   object_info = data->object_info;
749
750   g_string_append_printf (xml, "  <interface name=\"%s\">\n", name);
751
752   /* FIXME: recurse to parent types ? */
753   for (; methods; methods = methods->next)
754     {
755       DBusGMethodInfo *method;
756       const char *args;
757       method = methods->data;
758
759       g_string_append_printf (xml, "    <method name=\"%s\">\n",
760                               method_name_from_object_info (object_info, method));
761
762       args = method_arg_info_from_object_info (object_info, method);
763
764       while (*args)
765         {
766           const char *name;
767           gboolean arg_in;
768           const char *type;
769           
770           args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
771
772           /* FIXME - handle container types */
773           g_string_append_printf (xml, "      <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
774                                   name, type, arg_in ? "in" : "out");
775
776         }
777       g_string_append (xml, "    </method>\n");
778
779     }
780   g_slist_free (values->methods);
781
782   for (; signals; signals = signals->next)
783     {
784       guint id;
785       guint arg;
786       const char *signame;
787       GSignalQuery query;
788       char *s;
789
790       signame = signals->data;
791
792       s = _dbus_gutils_wincaps_to_uscore (signame);
793       
794       id = g_signal_lookup (s, data->gtype);
795       g_assert (id != 0);
796
797       g_signal_query (id, &query);
798       g_assert (query.return_type == G_TYPE_NONE);
799
800       g_string_append_printf (xml, "    <signal name=\"%s\">\n", signame);
801
802       for (arg = 0; arg < query.n_params; arg++)
803         {
804           char *dbus_type = _dbus_gtype_to_signature (query.param_types[arg]);
805
806           g_assert (dbus_type != NULL);
807
808           g_string_append (xml, "      <arg type=\"");
809           g_string_append (xml, dbus_type);
810           g_string_append (xml, "\"/>\n");
811           g_free (dbus_type);
812         }
813
814       g_string_append (xml, "    </signal>\n");
815       g_free (s);
816     }
817   g_slist_free (values->signals);
818
819   for (; properties; properties = properties->next)
820     {
821       const char *iface;
822       const char *propname;
823       const char *propname_uscore;
824       const char *access_type;
825       GParamSpec *spec;
826       char *dbus_type;
827       gboolean can_set;
828       gboolean can_get;
829       char *s;
830
831       spec = NULL;
832
833       property_iterate (properties->data, object_info->format_version, &iface, &propname, &propname_uscore, &access_type);
834
835       s = lookup_property_name (data->object, name, propname);
836
837       spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
838       g_assert (spec != NULL);
839       g_free (s);
840       
841       dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
842       g_assert (dbus_type != NULL);
843
844       can_set = strcmp (access_type, "readwrite") == 0
845                     && ((spec->flags & G_PARAM_WRITABLE) != 0
846                     && (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
847
848       can_get = (spec->flags & G_PARAM_READABLE) != 0;
849
850       if (can_set || can_get)
851         {
852           g_string_append_printf (xml, "    <property name=\"%s\" ", propname);
853           g_string_append (xml, "type=\"");
854           g_string_append (xml, dbus_type);
855           g_string_append (xml, "\" access=\"");
856
857           if (can_set && can_get)
858             g_string_append (xml, "readwrite");
859           else if (can_get)
860             g_string_append (xml, "read");
861           else
862             {
863               g_assert (can_set);
864               g_string_append (xml, "write");
865             }
866           
867           g_string_append (xml, "\"/>\n");
868         }
869       
870       g_free (dbus_type);
871     }
872   g_slist_free (values->properties);
873
874   g_free (values);
875   g_string_append (xml, "  </interface>\n");
876 }
877
878 static DBusGLibWriteInterfaceValues *
879 lookup_values (GHashTable *interfaces, const char *method_interface)
880 {
881   DBusGLibWriteInterfaceValues *values;
882   if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
883     {
884       values = g_new0 (DBusGLibWriteInterfaceValues, 1);
885       g_hash_table_insert (interfaces, (gpointer) method_interface, values);
886     }
887   return values;
888 }
889
890 static void
891 introspect_interfaces (GObject *object, GString *xml)
892 {
893   GList *info_list;
894   const GList *info_list_walk;
895   const DBusGObjectInfo *info;
896   DBusGLibWriteIterfaceData data;
897   int i;
898   GHashTable *interfaces;
899   DBusGLibWriteInterfaceValues *values;
900   const char *propsig;
901
902   info_list = lookup_object_info (object);
903
904   g_assert (info_list != NULL);
905
906   /* Gather a list of all interfaces, indexed into their methods */
907   for (info_list_walk = info_list; info_list_walk != NULL; info_list_walk = g_list_next (info_list_walk))
908     {
909       info = (DBusGObjectInfo *) info_list_walk->data;
910       interfaces = g_hash_table_new (g_str_hash, g_str_equal);
911       
912       g_assert (info != NULL);
913
914       for (i = 0; i < info->n_method_infos; i++)
915         {
916           const char *method_interface;
917           const DBusGMethodInfo *method;
918
919           method = &(info->method_infos[i]);
920
921           method_interface = method_interface_from_object_info (info, method);
922
923           values = lookup_values (interfaces, method_interface);
924           values->methods = g_slist_prepend (values->methods, (gpointer) method);
925         }
926
927       propsig = info->exported_signals;
928       while (propsig != NULL && *propsig)
929         {
930           const char *iface;
931           const char *signame;
932
933           propsig = signal_iterate (propsig, &iface, &signame);
934
935           values = lookup_values (interfaces, iface);
936           values->signals = g_slist_prepend (values->signals, (gpointer) signame);
937         }
938
939       propsig = info->exported_properties;
940       while (propsig != NULL && *propsig)
941         {
942           const char *iface;
943           const char *propname;
944           const char *propname_uscore;
945           const char *access_type;
946
947           propsig = property_iterate (propsig, info->format_version, &iface, &propname, &propname_uscore, &access_type);
948
949           values = lookup_values (interfaces, iface);
950           values->properties = g_slist_prepend (values->properties, (gpointer)iface);
951         }
952
953       memset (&data, 0, sizeof (data));
954       data.xml = xml;
955       data.gtype = G_TYPE_FROM_INSTANCE (object);
956       data.object_info = info;
957       data.object = object;
958
959       g_hash_table_foreach (interfaces, write_interface, &data);
960       g_hash_table_destroy (interfaces);
961     }
962
963   g_list_free (info_list);
964 }
965
966 static DBusHandlerResult
967 handle_introspect (DBusConnection *connection,
968                    DBusMessage    *message,
969                    GObject        *object)
970 {
971   GString *xml;
972   unsigned int i;
973   DBusMessage *ret;
974   char **children;
975   
976   if (!dbus_connection_list_registered (connection, 
977                                         dbus_message_get_path (message),
978                                         &children))
979     oom (NULL);
980   
981   xml = g_string_new (NULL);
982
983   g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
984   
985   g_string_append (xml, "<node>\n");
986
987   /* We are introspectable, though I guess that was pretty obvious */
988   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
989   g_string_append (xml, "    <method name=\"Introspect\">\n");
990   g_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
991   g_string_append (xml, "    </method>\n");
992   g_string_append (xml, "  </interface>\n");
993
994   /* We support get/set/getall properties */
995   g_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
996   g_string_append (xml, "    <method name=\"Get\">\n");
997   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
998   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
999   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
1000   g_string_append (xml, "    </method>\n");
1001   g_string_append (xml, "    <method name=\"Set\">\n");
1002   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
1003   g_string_append_printf (xml, "      <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
1004   g_string_append_printf (xml, "      <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
1005   g_string_append (xml, "    </method>\n");
1006   g_string_append (xml, "    <method name=\"GetAll\">\n");
1007   g_string_append_printf (xml, "      <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
1008   g_string_append_printf (xml, "      <arg name=\"props\" direction=\"out\" type=\"%s\"/>\n",
1009                           DBUS_TYPE_ARRAY_AS_STRING
1010                           DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1011                             DBUS_TYPE_STRING_AS_STRING
1012                             DBUS_TYPE_VARIANT_AS_STRING
1013                           DBUS_DICT_ENTRY_END_CHAR_AS_STRING
1014                           );
1015
1016   g_string_append (xml, "    </method>\n");
1017   g_string_append (xml, "  </interface>\n");
1018   
1019   introspect_interfaces (object, xml);
1020
1021   /* Append child nodes */
1022   for (i = 0; children[i]; i++)
1023       g_string_append_printf (xml, "  <node name=\"%s\"/>\n",
1024                               children[i]);
1025   
1026   /* Close the XML, and send it to the requesting app */
1027   g_string_append (xml, "</node>\n");
1028
1029   ret = reply_or_die (message);
1030
1031   dbus_message_append_args (ret,
1032                             DBUS_TYPE_STRING, &xml->str,
1033                             DBUS_TYPE_INVALID);
1034
1035   connection_send_or_die (connection, ret);
1036   dbus_message_unref (ret);
1037
1038   g_string_free (xml, TRUE);
1039
1040   dbus_free_string_array (children);
1041   
1042   return DBUS_HANDLER_RESULT_HANDLED;
1043 }
1044
1045 static DBusMessage*
1046 set_object_property (DBusConnection  *connection,
1047                      DBusMessage     *message,
1048                      DBusMessageIter *iter,
1049                      GObject         *object,
1050                      GParamSpec      *pspec)
1051 {
1052   GValue value = { 0, };
1053   DBusMessage *ret;
1054   DBusMessageIter sub;
1055   DBusGValueMarshalCtx context;
1056
1057   dbus_message_iter_recurse (iter, &sub);
1058
1059   context.recursion_depth = 0;
1060   context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
1061   context.proxy = NULL;
1062
1063   g_value_init (&value, pspec->value_type);
1064   if (_dbus_gvalue_demarshal (&context, &sub, &value, NULL))
1065     {
1066       g_object_set_property (object,
1067                              pspec->name,
1068                              &value);
1069
1070       g_value_unset (&value);
1071
1072       ret = reply_or_die (message);
1073     }
1074   else
1075     {
1076       ret = error_or_die (message,
1077           DBUS_ERROR_INVALID_ARGS,
1078           "Argument's D-BUS type can't be converted to a GType");
1079     }
1080
1081   return ret;
1082 }
1083
1084 /*
1085  * @pspec: the paramspec for a D-Bus-exported property
1086  *
1087  * Returns: a reply for the Get() D-Bus method, either successful or error
1088  */
1089 static DBusMessage*
1090 get_object_property (DBusConnection *connection,
1091                      DBusMessage    *message,
1092                      GObject        *object,
1093                      GParamSpec     *pspec)
1094 {
1095   GType value_gtype;
1096   GValue value = {0, };
1097   gchar *variant_sig;
1098   DBusMessage *ret;
1099   DBusMessageIter iter, subiter;
1100   gchar *error_message = NULL;
1101
1102   ret = reply_or_die (message);
1103
1104   g_value_init (&value, pspec->value_type);
1105   g_object_get_property (object, pspec->name, &value);
1106
1107   variant_sig = _dbus_gvalue_to_signature (&value);
1108   if (variant_sig == NULL)
1109     {
1110       value_gtype = G_VALUE_TYPE (&value);
1111       error_message = g_strdup_printf (
1112           "Internal error: cannot marshal type \"%s\" in variant",
1113           g_type_name (value_gtype));
1114       goto out;
1115     }
1116
1117   dbus_message_iter_init_append (ret, &iter);
1118   if (!dbus_message_iter_open_container (&iter,
1119                                          DBUS_TYPE_VARIANT,
1120                                          variant_sig,
1121                                          &subiter))
1122     {
1123       error_message = g_strdup_printf (
1124           "Internal error: cannot open variant container for signature %s",
1125           variant_sig);
1126       goto out;
1127     }
1128
1129   if (!_dbus_gvalue_marshal (&subiter, &value))
1130     {
1131       dbus_message_iter_abandon_container (&iter, &subiter);
1132       error_message = g_strdup_printf (
1133           "Internal error: could not marshal type \"%s\" in variant",
1134           G_VALUE_TYPE_NAME (&value));
1135       goto out;
1136     }
1137
1138   dbus_message_iter_close_container (&iter, &subiter);
1139
1140 out:
1141   g_value_unset (&value);
1142   g_free (variant_sig);
1143
1144   if (error_message != NULL)
1145     {
1146       dbus_message_unref (ret);
1147       ret = error_or_die (message, DBUS_ERROR_FAILED, error_message);
1148       g_critical ("%s", error_message);
1149       g_free (error_message);
1150     }
1151
1152   return ret;
1153 }
1154
1155 #define SHADOW_PROP_QUARK (dbus_g_object_type_dbus_shadow_property_quark ())
1156
1157 static GQuark
1158 dbus_g_object_type_dbus_shadow_property_quark (void)
1159 {
1160   static GQuark quark;
1161
1162   if (!quark)
1163     quark = g_quark_from_static_string ("DBusGObjectTypeDBusShadowPropertyQuark");
1164   return quark;
1165 }
1166
1167 /* Look for shadow properties on the given interface first, otherwise
1168  * just return the original property name.  This allows implementations to
1169  * get around the glib limitation of unique property names among all
1170  * GInterfaces by registering a "shadow" property name that the get/set
1171  * request will be redirected to.
1172  *
1173  * Shadow property data is stored as qdata on each GInterface.  If there
1174  * is no interface info, or there is no registered shadow property, just
1175  * return the original property name.
1176  */
1177 static char *
1178 lookup_property_name (GObject    *object,
1179                       const char *wincaps_propiface,
1180                       const char *requested_propname)
1181 {
1182   const DBusGObjectInfo *object_info;
1183   GHashTable *shadow_props;
1184   char *shadow_prop_name = NULL, *uscore_name;
1185   GType iface_type = 0;
1186
1187   g_assert (wincaps_propiface != NULL);
1188   g_assert (requested_propname != NULL);
1189
1190   uscore_name = _dbus_gutils_wincaps_to_uscore (requested_propname);
1191
1192   object_info = lookup_object_info_by_iface (object, wincaps_propiface, FALSE, &iface_type);
1193   if (!object_info)
1194     return uscore_name;
1195
1196   shadow_props = (GHashTable *) g_type_get_qdata (iface_type, SHADOW_PROP_QUARK);
1197   if (shadow_props)
1198     {
1199       shadow_prop_name = g_strdup (g_hash_table_lookup (shadow_props, requested_propname));
1200       if (shadow_prop_name)
1201         g_free (uscore_name);
1202     }
1203
1204   return shadow_prop_name ? shadow_prop_name : uscore_name;
1205 }
1206
1207 /**
1208  * dbus_g_object_type_register_shadow_property:
1209  * @iface_type: #GType for the #GInterface
1210  * @dbus_prop_name: D-Bus property name (as specified in the introspection data)
1211  *  to override with the shadow property name (as specified in the GType's
1212  *  initialization function, ie glib-style)
1213  * @shadow_prop_name: property name which should override the shadow property
1214  *
1215  * Registers a new property name @shadow_prop_name that overrides the
1216  * @dbus_prop_name in D-Bus property get/set requests.  Since all properties for
1217  * all interfaces implemented by a GObject exist in the same namespace, this
1218  * allows implementations to use the same property name in two or more D-Bus
1219  * interfaces implemented by the same GObject, as long as one of those D-Bus
1220  * interface properties is registered with a shadow property name.
1221  *
1222  * For example, if both org.foobar.Baz.InterfaceA and org.foobar.Baz.InterfaceB
1223  * have a D-Bus property called "Bork", the developer assigns a shadow property
1224  * name to the conflicting property name in one or both of these GInterfaces to
1225  * resolve the conflict.  Assume the GInterface implementing
1226  * org.foobar.Baz.InterfaceA registers a shadow property called "a-bork", while
1227  * the GInterface implementing org.foobar.Baz.InterfaceB registers a shadow
1228  * property called "b-bork".  The GObject implementing both these GInterfaces
1229  * would then use #g_object_class_override_property() to implement both
1230  * "a-bork" and "b-bork" and D-Bus requests for "Bork" on either D-Bus interface
1231  * will not conflict.
1232  */
1233 void
1234 dbus_g_object_type_register_shadow_property (GType      iface_type,
1235                                              const char *dbus_prop_name,
1236                                              const char *shadow_prop_name)
1237 {
1238   GHashTable *shadow_props;
1239
1240   g_return_if_fail (G_TYPE_IS_CLASSED (iface_type) || G_TYPE_IS_INTERFACE (iface_type));
1241   g_return_if_fail (dbus_prop_name != NULL);
1242   g_return_if_fail (shadow_prop_name != NULL);
1243
1244   shadow_props = (GHashTable *) g_type_get_qdata (iface_type, SHADOW_PROP_QUARK);
1245   if (!shadow_props)
1246     {
1247       shadow_props = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1248       g_type_set_qdata (iface_type,
1249                         dbus_g_object_type_dbus_shadow_property_quark (),
1250                         shadow_props);
1251     }
1252
1253   g_assert (shadow_props);
1254   g_hash_table_insert (shadow_props, g_strdup (dbus_prop_name), g_strdup (shadow_prop_name));
1255 }
1256
1257 static DBusMessage*
1258 get_all_object_properties (DBusConnection        *connection,
1259                            DBusMessage           *message,
1260                            const DBusGObjectInfo *object_info,
1261                            const char            *wincaps_propiface,
1262                            GObject               *object)
1263 {
1264   DBusMessage *ret;
1265   DBusMessageIter iter_ret;
1266   DBusMessageIter iter_dict;
1267   DBusMessageIter iter_dict_entry;
1268   DBusMessageIter iter_dict_value;
1269   const char *p;
1270   char *uscore_propname;
1271
1272   ret = reply_or_die (message);
1273
1274   dbus_message_iter_init_append (ret, &iter_ret);
1275
1276   /* the types are all hard-coded, so this can only fail via OOM */
1277   if (!dbus_message_iter_open_container (&iter_ret,
1278                                          DBUS_TYPE_ARRAY,
1279                                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1280                                          DBUS_TYPE_STRING_AS_STRING
1281                                          DBUS_TYPE_VARIANT_AS_STRING
1282                                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1283                                          &iter_dict))
1284     oom (NULL);
1285
1286   p = object_info->exported_properties;
1287   while (p != NULL && *p != '\0')
1288     {
1289       const char *prop_ifname;
1290       const char *prop_name;
1291       const char *prop_uscored;
1292       const char *access_flags;
1293       GParamSpec *pspec;
1294       GType value_gtype;
1295       GValue value = {0, };
1296       gchar *variant_sig;
1297
1298       p = property_iterate (p, object_info->format_version, &prop_ifname, &prop_name, &prop_uscored, &access_flags);
1299
1300       /* Conventionally, property names are valid member names, but dbus-glib
1301        * doesn't enforce this, and some dbus-glib services use GObject-style
1302        * property names (e.g. "foo-bar"). */
1303       if (!g_utf8_validate (prop_name, -1, NULL))
1304         {
1305           g_critical ("property name isn't UTF-8: %s", prop_name);
1306           continue;
1307         }
1308
1309       uscore_propname = lookup_property_name (object, wincaps_propiface, prop_name);
1310
1311       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), uscore_propname);
1312       if (pspec == NULL)
1313         {
1314           g_warning ("introspection data references non-existing property %s", uscore_propname);
1315           g_free (uscore_propname);
1316           continue;
1317         }
1318
1319       g_free (uscore_propname);
1320
1321       g_value_init (&value, pspec->value_type);
1322       g_object_get_property (object, pspec->name, &value);
1323
1324       variant_sig = _dbus_gvalue_to_signature (&value);
1325       if (variant_sig == NULL)
1326         {
1327           value_gtype = G_VALUE_TYPE (&value);
1328           g_warning ("Cannot marshal type \"%s\" in variant", g_type_name (value_gtype));
1329           g_value_unset (&value);
1330           continue;
1331         }
1332
1333       /* a signature returned by _dbus_gvalue_to_signature had better be
1334        * valid */
1335       g_assert (g_variant_is_signature (variant_sig));
1336
1337       /* type is hard-coded, so this can't fail except by OOM */
1338       if (!dbus_message_iter_open_container (&iter_dict,
1339                                              DBUS_TYPE_DICT_ENTRY,
1340                                              NULL,
1341                                              &iter_dict_entry))
1342         oom (NULL);
1343
1344       /* prop_name is valid UTF-8, so this can't fail except by OOM; no point
1345        * in abandoning @iter_dict_entry since we're about to crash out */
1346       if (!dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop_name))
1347         oom (NULL);
1348
1349       /* variant_sig has been asserted to be valid, so this can't fail
1350        * except by OOM */
1351       if (!dbus_message_iter_open_container (&iter_dict_entry,
1352                                              DBUS_TYPE_VARIANT,
1353                                              variant_sig,
1354                                              &iter_dict_value))
1355         oom (NULL);
1356
1357       g_free (variant_sig);
1358
1359       /* this can fail via programming error: the GObject property was
1360        * malformed (non-UTF8 string or something) */
1361       if (!_dbus_gvalue_marshal (&iter_dict_value, &value))
1362         {
1363           gchar *contents = g_strdup_value_contents (&value);
1364           gchar *error_message = g_strdup_printf (
1365               "cannot GetAll(%s): failed to serialize %s value of type %s: %s",
1366               wincaps_propiface, prop_name, G_VALUE_TYPE_NAME (&value),
1367               contents);
1368
1369           g_critical ("%s", error_message);
1370
1371           /* abandon ship! */
1372           dbus_message_iter_abandon_container (&iter_dict_entry,
1373               &iter_dict_value);
1374           dbus_message_iter_abandon_container (&iter_dict, &iter_dict_entry);
1375           dbus_message_unref (ret);
1376           ret = error_or_die (message, DBUS_ERROR_FAILED, error_message);
1377
1378           g_free (contents);
1379           g_free (error_message);
1380           g_value_unset (&value);
1381           return ret;
1382         }
1383
1384       /* these shouldn't fail except by OOM now that we were successful */
1385       if (!dbus_message_iter_close_container (&iter_dict_entry,
1386                                               &iter_dict_value))
1387         oom (NULL);
1388       if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry))
1389         oom (NULL);
1390
1391       g_value_unset (&value);
1392   }
1393
1394   if (!dbus_message_iter_close_container (&iter_ret, &iter_dict))
1395     oom (NULL);
1396
1397   return ret;
1398 }
1399
1400 static gboolean
1401 lookup_object_and_method (GObject      *object,
1402                           DBusMessage  *message,
1403                           const DBusGObjectInfo **object_ret,
1404                           const DBusGMethodInfo **method_ret)
1405 {
1406   const char *interface;
1407   const char *member;
1408   const char *signature;
1409   GList *info_list;
1410   const GList *info_list_walk;
1411   const DBusGObjectInfo *info;
1412   int i;
1413
1414   interface = dbus_message_get_interface (message);
1415   member = dbus_message_get_member (message);
1416   signature = dbus_message_get_signature (message);
1417
1418   info_list = lookup_object_info (object);
1419   
1420   for (info_list_walk = info_list; info_list_walk != NULL; info_list_walk = g_list_next (info_list_walk))
1421     {
1422       info = (DBusGObjectInfo *) info_list_walk->data;
1423       *object_ret = info;
1424
1425       for (i = 0; i < info->n_method_infos; i++)
1426         {
1427           const char *expected_member;
1428           const char *expected_interface;
1429           char *expected_signature;
1430           const DBusGMethodInfo *method;
1431
1432           method = &(info->method_infos[i]);
1433
1434           /* Check method interface/name and input signature */ 
1435           expected_interface = method_interface_from_object_info (*object_ret, method);
1436           expected_member = method_name_from_object_info (*object_ret, method);
1437           expected_signature = method_input_signature_from_object_info (*object_ret, method);
1438
1439           if ((interface == NULL
1440               || strcmp (expected_interface, interface) == 0)
1441               && strcmp (expected_member, member) == 0
1442               && strcmp (expected_signature, signature) == 0)
1443             {
1444               g_free (expected_signature);
1445               *method_ret = method;
1446               g_list_free (info_list);
1447               return TRUE;
1448             }
1449             g_free (expected_signature);
1450         }
1451     }
1452
1453   if (info_list)
1454     g_list_free (info_list);
1455
1456   return FALSE;
1457 }
1458
1459 static char *
1460 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
1461                                       const char *msg_interface,
1462                                       GQuark domain, gint code)
1463 {
1464   const char *domain_str;
1465   const char *code_str;
1466   GString *dbus_error_name;
1467
1468   domain_str = object_error_domain_prefix_from_object_info (object_info);
1469   code_str = object_error_code_from_object_info (object_info, domain, code);
1470
1471   if (!domain_str || !code_str)
1472     {
1473       DBusGErrorInfo *info;
1474
1475       g_static_rw_lock_reader_lock (&globals_lock);
1476
1477       if (error_metadata != NULL)
1478         info = g_datalist_id_get_data (&error_metadata, domain);
1479       else
1480         info = NULL;
1481
1482       g_static_rw_lock_reader_unlock (&globals_lock);
1483
1484       if (info)
1485         {
1486           GEnumValue *value;
1487           GEnumClass *klass;
1488
1489           klass = g_type_class_ref (info->code_enum);
1490           value = g_enum_get_value (klass, code);
1491           g_type_class_unref (klass);
1492
1493           domain_str = info->default_iface;
1494           if (value)
1495             {
1496               code_str = value->value_nick;
1497             }
1498           else
1499             {
1500               g_warning ("Error code %d out of range for GError domain %s",
1501                          code, g_quark_to_string (domain));
1502               code_str = NULL;
1503             }
1504         }
1505     }
1506
1507   if (!domain_str)
1508     domain_str = msg_interface;
1509
1510   if (!domain_str || !code_str)
1511     {
1512       const char *domain_string;
1513       /* If we can't map it sensibly, make up an error name */
1514       
1515       dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
1516
1517       domain_string = g_quark_to_string (domain);
1518       if (domain_string != NULL)
1519         {
1520           char *uscored = uscore_to_wincaps (domain_string);
1521           g_string_append (dbus_error_name, uscored);
1522           g_string_append_c (dbus_error_name, '.');
1523           g_free (uscored);
1524         }
1525
1526       /* Map -1 to (unsigned) -1 to avoid "-", which is not valid */
1527       g_string_append_printf (dbus_error_name, "Code%u", (unsigned) code);
1528     }
1529   else
1530     {
1531       gchar *code_str_wincaps;
1532       dbus_error_name = g_string_new (domain_str);
1533       g_string_append_c (dbus_error_name, '.');
1534       /* We can't uppercase here for backwards compatibility
1535        * reasons; if someone had a lowercase enumeration value,
1536        * previously we'd just send it across unaltered.
1537        */
1538       code_str_wincaps = uscore_to_wincaps_full (code_str, FALSE, FALSE);
1539       g_string_append (dbus_error_name, code_str_wincaps);
1540       g_free (code_str_wincaps);
1541     }
1542
1543   return g_string_free (dbus_error_name, FALSE);
1544 }
1545
1546 static DBusMessage *
1547 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
1548                               DBusMessage           *message,
1549                               const GError          *error)
1550 {
1551   DBusMessage *reply;
1552
1553   if (!error)
1554     {
1555       char *error_msg;
1556       
1557       error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
1558       reply = error_or_die (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
1559       g_free (error_msg);
1560     }
1561   else
1562     {
1563       if (error->domain == DBUS_GERROR)
1564         {
1565           const gchar *name = DBUS_ERROR_FAILED;
1566
1567           switch (error->code)
1568             {
1569             case DBUS_GERROR_FAILED:
1570               name = DBUS_ERROR_FAILED;
1571               break;
1572             case DBUS_GERROR_NO_MEMORY:
1573               name = DBUS_ERROR_NO_MEMORY;
1574               break;
1575             case DBUS_GERROR_SERVICE_UNKNOWN:
1576               name = DBUS_ERROR_SERVICE_UNKNOWN;
1577               break;
1578             case DBUS_GERROR_NAME_HAS_NO_OWNER:
1579               name = DBUS_ERROR_NAME_HAS_NO_OWNER;
1580               break;
1581             case DBUS_GERROR_NO_REPLY:
1582               name = DBUS_ERROR_NO_REPLY;
1583               break;
1584             case DBUS_GERROR_IO_ERROR:
1585               name = DBUS_ERROR_IO_ERROR;
1586               break;
1587             case DBUS_GERROR_BAD_ADDRESS:
1588               name = DBUS_ERROR_BAD_ADDRESS;
1589               break;
1590             case DBUS_GERROR_NOT_SUPPORTED:
1591               name = DBUS_ERROR_NOT_SUPPORTED;
1592               break;
1593             case DBUS_GERROR_LIMITS_EXCEEDED:
1594               name = DBUS_ERROR_LIMITS_EXCEEDED;
1595               break;
1596             case DBUS_GERROR_ACCESS_DENIED:
1597               name = DBUS_ERROR_ACCESS_DENIED;
1598               break;
1599             case DBUS_GERROR_AUTH_FAILED:
1600               name = DBUS_ERROR_AUTH_FAILED;
1601               break;
1602             case DBUS_GERROR_NO_SERVER:
1603               name = DBUS_ERROR_NO_SERVER;
1604               break;
1605             case DBUS_GERROR_TIMEOUT:
1606               name = DBUS_ERROR_TIMEOUT;
1607               break;
1608             case DBUS_GERROR_NO_NETWORK:
1609               name = DBUS_ERROR_NO_NETWORK;
1610               break;
1611             case DBUS_GERROR_ADDRESS_IN_USE:
1612               name = DBUS_ERROR_ADDRESS_IN_USE;
1613               break;
1614             case DBUS_GERROR_DISCONNECTED:
1615               name = DBUS_ERROR_DISCONNECTED;
1616               break;
1617             case DBUS_GERROR_INVALID_ARGS:
1618               name = DBUS_ERROR_INVALID_ARGS;
1619               break;
1620             case DBUS_GERROR_FILE_NOT_FOUND:
1621               name = DBUS_ERROR_FILE_NOT_FOUND;
1622               break;
1623             case DBUS_GERROR_REMOTE_EXCEPTION:
1624               name = dbus_g_error_get_name ((GError*) error);
1625               break;
1626             }
1627
1628           reply = error_or_die (message, name, error->message);
1629         }
1630       else
1631         {
1632           char *error_name;
1633           error_name = gerror_domaincode_to_dbus_error_name (object_info,
1634                                                              dbus_message_get_interface (message),
1635                                                              error->domain, error->code);
1636           reply = error_or_die (message, error_name, error->message);
1637           g_free (error_name);
1638         }
1639     }
1640
1641   return reply;
1642 }
1643
1644 /**
1645  * SECTION:dbus-gmethod
1646  * @short_description: GMethod Info & Invocation
1647  * @see_also: #DBusGMessage
1648  * @stability: Stable
1649  *
1650  * These types are used to call methods on #GObject objects.
1651  */
1652
1653 /**
1654  * DBusGMethodInvocation:
1655  *
1656  * The context of an asynchronous method call.  See dbus_g_method_return() and
1657  * dbus_g_method_return_error().
1658  */
1659 struct _DBusGMethodInvocation {
1660   DBusGConnection *connection; /**< The connection */
1661   DBusGMessage *message; /**< The message which generated the method call */
1662   const DBusGObjectInfo *object; /**< The object the method was called on */
1663   const DBusGMethodInfo *method; /**< The method called */
1664   gboolean send_reply;
1665 };
1666
1667 static DBusHandlerResult
1668 invoke_object_method (GObject         *object,
1669                       const DBusGObjectInfo *object_info,
1670                       const DBusGMethodInfo *method,
1671                       DBusConnection  *connection,
1672                       DBusMessage     *message)
1673 {
1674   gboolean had_error, is_async, send_reply;
1675   GError *gerror;
1676   GValueArray *value_array;
1677   GValue return_value = {0,};
1678   GClosure closure;
1679   char *in_signature;
1680   GArray *out_param_values = NULL;
1681   GValueArray *out_param_gvalues = NULL;
1682   int out_param_count;
1683   int out_param_pos, out_param_gvalue_pos;
1684   DBusMessage *reply = NULL;
1685   gboolean have_retval;
1686   gboolean retval_signals_error;
1687   gboolean retval_is_synthetic;
1688   gboolean retval_is_constant;
1689   const char *arg_metadata;
1690
1691   gerror = NULL;
1692
1693   /* This flag says whether invokee is handed a special DBusGMethodInvocation structure,
1694    * instead of being required to fill out all return values in the context of the function.
1695    * Some additional data is also exposed, such as the message sender.
1696    */
1697   is_async = strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0;
1698   
1699   /* Messages can be sent with a flag that says "I don't need a reply".  This is an optimization
1700    * normally, but in the context of the system bus it's important to not send a reply
1701    * to these kinds of messages, because they will be unrequested replies, and thus subject
1702    * to denial and logging.  We don't want to fill up logs.
1703    * http://bugs.freedesktop.org/show_bug.cgi?id=19441
1704    */
1705   send_reply = !dbus_message_get_no_reply (message); 
1706
1707   have_retval = FALSE;
1708   retval_signals_error = FALSE;
1709   retval_is_synthetic = FALSE;
1710   retval_is_constant = FALSE;
1711
1712   /* This is evil.  We do this to work around the fact that
1713    * the generated glib marshallers check a flag in the closure object
1714    * which we don't care about.  We don't need/want to create
1715    * a new closure for each invocation.
1716    */
1717   memset (&closure, 0, sizeof (closure));
1718
1719   in_signature = method_input_signature_from_object_info (object_info, method); 
1720   
1721   /* Convert method IN parameters to GValueArray */
1722   {
1723     GArray *types_array;
1724     guint n_params;
1725     const GType *types;
1726     DBusGValueMarshalCtx context;
1727     GError *error = NULL;
1728     
1729     context.recursion_depth = 0;
1730     context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
1731     context.proxy = NULL;
1732
1733     types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
1734     n_params = types_array->len;
1735     types = (const GType*) types_array->data;
1736
1737     value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
1738     if (value_array == NULL)
1739       {
1740         g_free (in_signature); 
1741         g_array_free (types_array, TRUE);
1742         reply = error_or_die (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
1743         connection_send_or_die (connection, reply);
1744         dbus_message_unref (reply);
1745         g_error_free (error);
1746         return DBUS_HANDLER_RESULT_HANDLED;
1747       }
1748     g_array_free (types_array, TRUE);
1749   }
1750
1751   /* Prepend object as first argument */ 
1752   g_value_array_prepend (value_array, NULL);
1753   g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
1754   g_value_set_object (g_value_array_get_nth (value_array, 0), object);
1755   
1756   if (is_async)
1757     {
1758       GValue context_value = {0,};
1759       DBusGMethodInvocation *context;
1760       context = g_new (DBusGMethodInvocation, 1);
1761       context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
1762       context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
1763       context->object = object_info;
1764       context->method = method;
1765       context->send_reply = send_reply;
1766       g_value_init (&context_value, G_TYPE_POINTER);
1767       g_value_set_pointer (&context_value, context);
1768       g_value_array_append (value_array, &context_value);
1769     }
1770   else
1771     {
1772       RetvalType retval;
1773       gboolean arg_in;
1774       gboolean arg_const;
1775       const char *argsig;
1776
1777       arg_metadata = method_arg_info_from_object_info (object_info, method);
1778       
1779       /* Count number of output parameters, and look for a return value */
1780       out_param_count = 0;
1781       while (*arg_metadata)
1782         {
1783           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
1784           if (arg_in)
1785             continue;
1786           if (retval != RETVAL_NONE)
1787             {
1788               DBusSignatureIter tmp_sigiter;
1789               /* This is the function return value */
1790               g_assert (!have_retval);
1791               have_retval = TRUE;
1792               retval_is_synthetic = FALSE;
1793
1794               switch (retval)
1795                 {
1796                 case RETVAL_NONE:
1797                   g_assert_not_reached ();
1798                   break;
1799                 case RETVAL_NOERROR:
1800                   retval_signals_error = FALSE;
1801                   break;
1802                 case RETVAL_ERROR:
1803                   retval_signals_error = TRUE;
1804                   break;
1805                 }
1806
1807               retval_is_constant = arg_const;
1808
1809               /* Initialize our return GValue with the specified type */
1810               dbus_signature_iter_init (&tmp_sigiter, argsig);
1811               g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
1812             }
1813           else
1814             {
1815               /* It's a regular output value */
1816               out_param_count++;
1817             }
1818         }
1819
1820       /* For compatibility, if we haven't found a return value, we assume
1821        * the function returns a gboolean for signalling an error
1822        * (and therefore also takes a GError).  We also note that it
1823        * is a "synthetic" return value; i.e. we aren't going to be
1824        * sending it over the bus, it's just to signal an error.
1825        */
1826       if (!have_retval)
1827         {
1828           have_retval = TRUE;
1829           retval_is_synthetic = TRUE;
1830           retval_signals_error = TRUE;
1831           g_value_init (&return_value, G_TYPE_BOOLEAN);
1832         }
1833
1834       /* Create an array to store the actual values of OUT parameters
1835        * (other than the real function return, if any).  Then, create
1836        * a GValue boxed POINTER to each of those values, and append to
1837        * the invocation, so the method can return the OUT parameters.
1838        */
1839       out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
1840
1841       /* We have a special array of GValues for toplevel GValue return
1842        * types.
1843        */
1844       out_param_gvalues = g_value_array_new (out_param_count);
1845       out_param_pos = 0;
1846       out_param_gvalue_pos = 0;
1847
1848       /* Reset argument metadata pointer */
1849       arg_metadata = method_arg_info_from_object_info (object_info, method);
1850       
1851       /* Iterate over output arguments again, this time allocating space for
1852        * them as appopriate.
1853        */
1854       while (*arg_metadata)
1855         {
1856           GValue value = {0, };
1857           GTypeCValue storage;
1858           DBusSignatureIter tmp_sigiter;
1859           GType current_gtype;
1860
1861           arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
1862           /* Skip over input arguments and the return value, if any */
1863           if (arg_in || retval != RETVAL_NONE)
1864             continue;
1865
1866           dbus_signature_iter_init (&tmp_sigiter, argsig);
1867           current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
1868
1869           g_value_init (&value, G_TYPE_POINTER);
1870
1871           /* We special case variants to make method invocation a bit nicer */
1872           if (current_gtype != G_TYPE_VALUE)
1873             {
1874               memset (&storage, 0, sizeof (storage));
1875               g_array_append_val (out_param_values, storage);
1876               g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
1877               out_param_pos++;
1878             }
1879           else
1880             {
1881               g_value_array_append (out_param_gvalues, NULL);
1882               g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
1883               out_param_gvalue_pos++;
1884             }
1885           g_value_array_append (value_array, &value);
1886         }
1887     }
1888
1889   /* Append GError as final argument if necessary */
1890   if (retval_signals_error)
1891     {
1892       g_assert (have_retval);
1893       g_value_array_append (value_array, NULL);
1894       g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
1895       g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
1896     }
1897   
1898   /* Actually invoke method */
1899   method->marshaller (&closure, have_retval ? &return_value : NULL,
1900                       value_array->n_values,
1901                       value_array->values,
1902                       NULL, method->function);
1903   if (is_async)
1904     {
1905       goto done;
1906     }
1907
1908   if (retval_signals_error)
1909     had_error = _dbus_gvalue_signals_error (&return_value);
1910   else
1911     had_error = FALSE;
1912
1913   if (!had_error)
1914     {
1915       DBusMessageIter iter;
1916
1917       /* Careful here - there are two major cases in this section of the code.
1918        * If send_reply is TRUE, we're constructing a dbus message and freeing
1919        * the return values.  If it's FALSE, then we just need to free the
1920        * values.
1921        */
1922       if (send_reply)
1923         {
1924           reply = reply_or_die (message);
1925
1926           /* Append output arguments to reply */
1927           dbus_message_iter_init_append (reply, &iter);
1928         }
1929
1930       /* First, append the return value, unless it's synthetic */
1931       if (have_retval && !retval_is_synthetic)
1932         {
1933           if (reply != NULL && !_dbus_gvalue_marshal (&iter, &return_value))
1934             {
1935               gchar *desc = g_strdup_value_contents (&return_value);
1936
1937               g_critical ("unable to append retval of type %s for %s: %s",
1938                   G_VALUE_TYPE_NAME (&return_value),
1939                   method_name_from_object_info (object_info, method),
1940                   desc);
1941               g_free (desc);
1942               /* the reply is now unusable but we still need to free
1943                * everything */
1944               dbus_message_unref (reply);
1945               reply = NULL;
1946             }
1947
1948           if (!retval_is_constant)
1949             g_value_unset (&return_value);
1950         }
1951
1952       /* Grab the argument metadata and iterate over it */
1953       arg_metadata = method_arg_info_from_object_info (object_info, method);
1954       
1955       /* Now append any remaining return values */
1956       out_param_pos = 0;
1957       out_param_gvalue_pos = 0;
1958       while (*arg_metadata)
1959         {
1960           GValue gvalue = {0, };
1961           const char *arg_name;
1962           gboolean arg_in;
1963           gboolean constval;
1964           RetvalType retval;
1965           const char *arg_signature;
1966           DBusSignatureIter argsigiter;
1967
1968           do
1969             {
1970               /* Iterate over only output values; skip over input
1971                  arguments and the return value */
1972               arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
1973             }
1974           while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
1975
1976           /* If the last argument we saw was input or the return
1977            * value, we must be done iterating over output arguments.
1978            */
1979           if (arg_in || retval != RETVAL_NONE)
1980             break;
1981
1982           dbus_signature_iter_init (&argsigiter, arg_signature);
1983           
1984           g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
1985           if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
1986             {
1987               if (!_dbus_gvalue_take (&gvalue,
1988                                      &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
1989                 g_assert_not_reached ();
1990               out_param_pos++;
1991             }
1992           else
1993             {
1994               g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
1995               out_param_gvalue_pos++;
1996             }
1997
1998           if (reply && !_dbus_gvalue_marshal (&iter, &gvalue))
1999             {
2000               gchar *desc = g_strdup_value_contents (&gvalue);
2001
2002               g_critical ("unable to append OUT arg of type %s for %s: %s",
2003                   G_VALUE_TYPE_NAME (&gvalue),
2004                   method_name_from_object_info (object_info, method),
2005                   desc);
2006               g_free (desc);
2007               /* the reply is now unusable but we still need to free
2008                * everything */
2009               dbus_message_unref (reply);
2010               reply = NULL;
2011             }
2012
2013           /* Here we actually free the allocated value; we
2014            * took ownership of it with _dbus_gvalue_take, unless
2015            * an annotation has specified this value as constant.
2016            */
2017           if (!constval)
2018             g_value_unset (&gvalue);
2019         }
2020     }
2021   else if (send_reply)
2022     reply = gerror_to_dbus_error_message (object_info, message, gerror);
2023
2024   if (reply)
2025     {
2026       connection_send_or_die (connection, reply);
2027       dbus_message_unref (reply);
2028     }
2029
2030 done:
2031   g_free (in_signature);
2032
2033   if (!is_async)
2034     {
2035       g_array_free (out_param_values, TRUE);
2036       g_value_array_free (out_param_gvalues);
2037     }
2038
2039   if (gerror != NULL)
2040     g_clear_error (&gerror);
2041
2042   g_value_array_free (value_array);
2043   return DBUS_HANDLER_RESULT_HANDLED;
2044 }
2045
2046 /*
2047  * @wincaps_propiface: the D-Bus interface name, conventionally WindowsCaps
2048  * @requested_propname: the D-Bus property name, conventionally WindowsCaps
2049  * @uscore_propname: the GObject property name, conventionally
2050  *    words_with_underscores or words-with-dashes
2051  * @is_set: %TRUE if we're going to set the property, %FALSE if we're going
2052  *    to get it
2053  *
2054  * Check that the requested property exists and the requested access is
2055  * allowed. If not, reply with a D-Bus AccessDenied error message.
2056  *
2057  * Returns: %TRUE if property access can continue, or %FALSE if an error
2058  *    reply has been sent
2059  */
2060 static gboolean
2061 check_property_access (DBusConnection  *connection,
2062                        DBusMessage     *message,
2063                        GObject         *object,
2064                        const char      *wincaps_propiface,
2065                        const char      *requested_propname,
2066                        const char      *uscore_propname,
2067                        gboolean         is_set)
2068 {
2069   const DBusGObjectInfo *object_info;
2070   const char *access_type;
2071   DBusMessage *ret;
2072   gchar *error_message;
2073
2074   if (!is_set && !disable_legacy_property_access)
2075     return TRUE;
2076
2077   object_info = lookup_object_info_by_iface (object, wincaps_propiface, TRUE, NULL);
2078   if (!object_info)
2079     {
2080       error_message = g_strdup_printf (
2081           "Interface \"%s\" isn't exported (or may not exist), can't access property \"%s\"",
2082           wincaps_propiface, requested_propname);
2083
2084       goto error;
2085     }
2086
2087   /* Try both forms of property names: "foo_bar" or "FooBar"; for historical
2088    * reasons we accept both.
2089    */
2090   if (object_info
2091       && !(property_info_from_object_info (object_info, wincaps_propiface, requested_propname, &access_type)
2092            || property_info_from_object_info (object_info, wincaps_propiface, uscore_propname, &access_type)))
2093     {
2094       error_message = g_strdup_printf (
2095           "Property \"%s\" of interface \"%s\" isn't exported (or may not exist)",
2096           requested_propname, wincaps_propiface);
2097
2098       goto error;
2099     }
2100
2101   if (strcmp (access_type, "readwrite") == 0)
2102     return TRUE;
2103
2104   if (is_set ? strcmp (access_type, "read") == 0
2105              : strcmp (access_type, "write") == 0)
2106     {
2107       error_message = g_strdup_printf (
2108           "Property \"%s\" of interface \"%s\" is not %s",
2109           requested_propname,
2110           wincaps_propiface,
2111           is_set ? "settable" : "readable");
2112
2113       goto error;
2114     }
2115
2116   return TRUE;
2117
2118 error:
2119   ret = error_or_die (message, DBUS_ERROR_ACCESS_DENIED, error_message);
2120   g_free (error_message);
2121
2122   connection_send_or_die (connection, ret);
2123   dbus_message_unref (ret);
2124   return FALSE;
2125 }
2126
2127 static DBusHandlerResult
2128 object_registration_message (DBusConnection  *connection,
2129                              DBusMessage     *message,
2130                              void            *user_data)
2131 {
2132   GParamSpec *pspec;
2133   GObject *object;
2134   gboolean setter;
2135   gboolean getter;
2136   gboolean getall;
2137   char *s;
2138   const char *requested_propname;
2139   const char *wincaps_propiface;
2140   DBusMessageIter iter;
2141   const DBusGMethodInfo *method;
2142   const DBusGObjectInfo *object_info;
2143   DBusMessage *ret;
2144   ObjectRegistration *o;
2145
2146   o = user_data;
2147   /* export is always non-NULL. If the object has been disposed, the weak-ref
2148    * callback removes all registrations from the DBusConnection, so this
2149    * should never be reached with object = NULL. */
2150   object = G_OBJECT (o->export->object);
2151   g_assert (object != NULL);
2152
2153   if (dbus_message_is_method_call (message,
2154                                    DBUS_INTERFACE_INTROSPECTABLE,
2155                                    "Introspect"))
2156     return handle_introspect (connection, message, object);
2157
2158   /* Try the metainfo, which lets us invoke methods */
2159   object_info = NULL;
2160   if (lookup_object_and_method (object, message, &object_info, &method))
2161     return invoke_object_method (object, object_info, method, connection, message);
2162
2163   /* If no metainfo, we can still do properties and signals
2164    * via standard GLib introspection.  Note we do now check
2165    * property access against the metainfo if available.
2166    */
2167   getter = FALSE;
2168   setter = FALSE;
2169   getall = FALSE;
2170   if (dbus_message_is_method_call (message,
2171                                    DBUS_INTERFACE_PROPERTIES,
2172                                    "Get"))
2173     getter = TRUE;
2174   else if (dbus_message_is_method_call (message,
2175                                         DBUS_INTERFACE_PROPERTIES,
2176                                         "Set"))
2177     setter = TRUE;
2178   else if (dbus_message_is_method_call (message,
2179                                    DBUS_INTERFACE_PROPERTIES,
2180                                    "GetAll"))
2181     getall = TRUE;
2182
2183   if (!(setter || getter || getall))
2184     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2185
2186   ret = NULL;
2187
2188   dbus_message_iter_init (message, &iter);
2189
2190   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
2191     {
2192       ret = error_or_die (message, DBUS_ERROR_INVALID_ARGS,
2193           "First argument to Get(), GetAll() or Set() must be an interface string");
2194       goto out;
2195     }
2196
2197   dbus_message_iter_get_basic (&iter, &wincaps_propiface);
2198   dbus_message_iter_next (&iter);
2199
2200   if (getall)
2201     {
2202       object_info = lookup_object_info_by_iface (object, wincaps_propiface, TRUE, NULL);
2203       if (object_info != NULL)
2204           ret = get_all_object_properties (connection, message, object_info, wincaps_propiface, object);
2205       else
2206           return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2207     }
2208   else
2209     {
2210       g_assert (getter || setter);
2211
2212       if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
2213         {
2214           ret = error_or_die (message, DBUS_ERROR_INVALID_ARGS,
2215               "Second argument to Get() or Set() must be a property name string");
2216           goto out;
2217         }
2218
2219       dbus_message_iter_get_basic (&iter, &requested_propname);
2220       dbus_message_iter_next (&iter);
2221
2222       s = lookup_property_name (object, wincaps_propiface, requested_propname);
2223
2224       if (!check_property_access (connection, message, object, wincaps_propiface, requested_propname, s, setter))
2225         {
2226           g_free (s);
2227           return DBUS_HANDLER_RESULT_HANDLED;
2228         }
2229
2230       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
2231                                             s);
2232
2233       g_free (s);
2234
2235       if (pspec != NULL)
2236         {
2237           if (setter)
2238             {
2239               if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
2240                 {
2241                   ret = error_or_die (message, DBUS_ERROR_INVALID_ARGS,
2242                       "Third argument to Set() must be a variant");
2243                   goto out;
2244                 }
2245
2246               ret = set_object_property (connection, message, &iter,
2247                                          object, pspec);
2248               dbus_message_iter_next (&iter);
2249             }
2250           else
2251             {
2252               g_assert (getter);
2253               ret = get_object_property (connection, message,
2254                                          object, pspec);
2255             }
2256         }
2257       else
2258         {
2259           gchar *error_message = g_strdup_printf ("No such property %s",
2260               requested_propname);
2261
2262           ret = error_or_die (message, DBUS_ERROR_INVALID_ARGS, error_message);
2263           g_free (error_message);
2264         }
2265     }
2266
2267   g_assert (ret != NULL);
2268
2269   /* FIXME: this should be returned as a D-Bus error, not spammed out
2270    * as a warning. This is too late to do that, though - we've already
2271    * had any side-effects we were going to have - and it would break
2272    * anything that's relying on ability to give us too many arguments. */
2273   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
2274     g_warning ("Property get, set or set all had too many arguments\n");
2275
2276 out:
2277   connection_send_or_die (connection, ret);
2278   dbus_message_unref (ret);
2279   return DBUS_HANDLER_RESULT_HANDLED;
2280 }
2281
2282 static const DBusObjectPathVTable gobject_dbus_vtable = {
2283   object_registration_unregistered,
2284   object_registration_message,
2285   NULL
2286 };
2287
2288 typedef struct {
2289   GClosure         closure;
2290   DBusGConnection *connection;
2291   GObject         *object;
2292   const char      *signame;
2293   const char      *sigiface;
2294 } DBusGSignalClosure;
2295
2296 static GClosure *
2297 dbus_g_signal_closure_new (GObject         *object,
2298                            const char      *signame,
2299                            const char      *sigiface)
2300 {
2301   DBusGSignalClosure *closure;
2302   
2303   closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
2304
2305   closure->object = object;
2306   closure->signame = signame;
2307   closure->sigiface = sigiface;
2308   return (GClosure*) closure;
2309 }
2310
2311 static void
2312 emit_signal_for_registration (ObjectRegistration *o,
2313                               DBusGSignalClosure *sigclosure,
2314                               GValue             *retval,
2315                               guint               n_param_values,
2316                               const GValue       *param_values)
2317 {
2318   DBusMessage *signal;
2319   DBusMessageIter iter;
2320   guint i;
2321
2322   g_assert (g_variant_is_object_path (o->object_path));
2323   g_assert (g_dbus_is_interface_name (sigclosure->sigiface));
2324   g_assert (g_dbus_is_member_name (sigclosure->signame));
2325
2326   signal = dbus_message_new_signal (o->object_path,
2327                                     sigclosure->sigiface,
2328                                     sigclosure->signame);
2329   if (!signal)
2330     oom (NULL);
2331
2332   dbus_message_iter_init_append (signal, &iter);
2333
2334   /* First argument is the object itself, and we can't marshall that */
2335   for (i = 1; i < n_param_values; i++)
2336     {
2337       if (!_dbus_gvalue_marshal (&iter,
2338                                 (GValue *) (&(param_values[i]))))
2339         {
2340           g_warning ("failed to marshal parameter %d for signal %s",
2341                      i, sigclosure->signame);
2342           goto out;
2343         }
2344     }
2345
2346   connection_send_or_die (DBUS_CONNECTION_FROM_G_CONNECTION (o->connection),
2347       signal);
2348 out:
2349   dbus_message_unref (signal);
2350 }
2351
2352 static void
2353 signal_emitter_marshaller (GClosure        *closure,
2354                            GValue          *retval,
2355                            guint            n_param_values,
2356                            const GValue    *param_values,
2357                            gpointer         invocation_hint,
2358                            gpointer         marshal_data)
2359 {
2360   DBusGSignalClosure *sigclosure;
2361   const ObjectExport *oe;
2362   const GSList *iter;
2363
2364   sigclosure = (DBusGSignalClosure *) closure;
2365
2366   g_assert (retval == NULL);
2367
2368   oe = g_object_get_data (sigclosure->object, "dbus_glib_object_registrations");
2369   /* If the object has ever been exported, this should exist; it persists until
2370    * the object is actually freed. */
2371   g_assert (oe != NULL);
2372
2373   for (iter = oe->registrations; iter; iter = iter->next)
2374     {
2375       ObjectRegistration *o = iter->data;
2376
2377       emit_signal_for_registration (o, sigclosure, retval, n_param_values, param_values);
2378     }
2379 }
2380
2381 static void
2382 export_signals (const GList *info_list, GObject *object)
2383 {
2384   GType gtype;
2385   const char *sigdata;
2386   const char *iface;
2387   const char *signame;
2388   const DBusGObjectInfo *info;
2389
2390   gtype = G_TYPE_FROM_INSTANCE (object);
2391
2392   for (; info_list != NULL; info_list = g_list_next (info_list))
2393     {
2394       info = (DBusGObjectInfo *) info_list->data;
2395       
2396       sigdata = info->exported_signals;
2397       
2398       while (*sigdata != '\0')
2399         {
2400           guint id;
2401           GSignalQuery query;
2402           GClosure *closure;
2403           char *s;
2404
2405           sigdata = signal_iterate (sigdata, &iface, &signame);
2406
2407           if (!g_dbus_is_interface_name (iface))
2408             {
2409               g_critical ("invalid interface name found in %s: %s",
2410                   g_type_name (gtype), iface);
2411               continue;
2412             }
2413
2414           if (!g_dbus_is_member_name (signame))
2415             {
2416               g_critical ("invalid signal name found in %s: %s",
2417                   g_type_name (gtype), signame);
2418               continue;
2419             }
2420
2421           s = _dbus_gutils_wincaps_to_uscore (signame);
2422
2423           id = g_signal_lookup (s, gtype);
2424           if (id == 0)
2425             {
2426               g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
2427                      s, signame, g_type_name (gtype));
2428               g_free (s);
2429               continue;
2430             }
2431
2432           g_signal_query (id, &query);
2433
2434           if (query.return_type != G_TYPE_NONE)
2435             {
2436               g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
2437                      s, g_type_name (gtype), g_type_name (query.return_type));
2438               g_free (s);
2439               continue; /* FIXME: these could be listed as methods ? */
2440             }
2441           
2442           closure = dbus_g_signal_closure_new (object, signame, (char*) iface);
2443           g_closure_set_marshal (closure, signal_emitter_marshaller);
2444
2445           g_signal_connect_closure_by_id (object,
2446                           id,
2447                           0,
2448                           closure,
2449                           FALSE);
2450
2451           g_free (s);
2452         }
2453     }
2454 }
2455
2456 static gint
2457 dbus_error_to_gerror_code (const char *derr)
2458 {
2459   if (0) ; 
2460   else if (!strcmp (derr,  DBUS_ERROR_FAILED  )) 
2461     return  DBUS_GERROR_FAILED ;
2462   else if (!strcmp (derr,  DBUS_ERROR_NO_MEMORY  )) 
2463     return  DBUS_GERROR_NO_MEMORY ;
2464   else if (!strcmp (derr,  DBUS_ERROR_SERVICE_UNKNOWN  )) 
2465     return  DBUS_GERROR_SERVICE_UNKNOWN ;
2466   else if (!strcmp (derr,  DBUS_ERROR_NAME_HAS_NO_OWNER  )) 
2467     return  DBUS_GERROR_NAME_HAS_NO_OWNER ;
2468   else if (!strcmp (derr,  DBUS_ERROR_NO_REPLY  )) 
2469     return  DBUS_GERROR_NO_REPLY ;
2470   else if (!strcmp (derr,  DBUS_ERROR_IO_ERROR  )) 
2471     return  DBUS_GERROR_IO_ERROR ;
2472   else if (!strcmp (derr,  DBUS_ERROR_BAD_ADDRESS  )) 
2473     return  DBUS_GERROR_BAD_ADDRESS ;
2474   else if (!strcmp (derr,  DBUS_ERROR_NOT_SUPPORTED  )) 
2475     return  DBUS_GERROR_NOT_SUPPORTED ;
2476   else if (!strcmp (derr,  DBUS_ERROR_LIMITS_EXCEEDED  )) 
2477     return  DBUS_GERROR_LIMITS_EXCEEDED ;
2478   else if (!strcmp (derr,  DBUS_ERROR_ACCESS_DENIED  )) 
2479     return  DBUS_GERROR_ACCESS_DENIED ;
2480   else if (!strcmp (derr,  DBUS_ERROR_AUTH_FAILED  )) 
2481     return  DBUS_GERROR_AUTH_FAILED ;
2482   else if (!strcmp (derr,  DBUS_ERROR_NO_SERVER  )) 
2483     return  DBUS_GERROR_NO_SERVER ;
2484   else if (!strcmp (derr,  DBUS_ERROR_TIMEOUT  )) 
2485     return  DBUS_GERROR_TIMEOUT ;
2486   else if (!strcmp (derr,  DBUS_ERROR_NO_NETWORK  )) 
2487     return  DBUS_GERROR_NO_NETWORK ;
2488   else if (!strcmp (derr,  DBUS_ERROR_ADDRESS_IN_USE  )) 
2489     return  DBUS_GERROR_ADDRESS_IN_USE ;
2490   else if (!strcmp (derr,  DBUS_ERROR_DISCONNECTED  )) 
2491     return  DBUS_GERROR_DISCONNECTED ;
2492   else if (!strcmp (derr,  DBUS_ERROR_INVALID_ARGS  )) 
2493     return  DBUS_GERROR_INVALID_ARGS ;
2494   else if (!strcmp (derr,  DBUS_ERROR_FILE_NOT_FOUND  )) 
2495     return  DBUS_GERROR_FILE_NOT_FOUND ;
2496   else if (!strcmp (derr,  DBUS_ERROR_FILE_EXISTS  )) 
2497     return  DBUS_GERROR_FILE_EXISTS ;
2498   else if (!strcmp (derr,  DBUS_ERROR_UNKNOWN_METHOD  )) 
2499     return  DBUS_GERROR_UNKNOWN_METHOD ;
2500   else if (!strcmp (derr,  DBUS_ERROR_TIMED_OUT  )) 
2501     return  DBUS_GERROR_TIMED_OUT ;
2502   else if (!strcmp (derr,  DBUS_ERROR_MATCH_RULE_NOT_FOUND  )) 
2503     return  DBUS_GERROR_MATCH_RULE_NOT_FOUND ;
2504   else if (!strcmp (derr,  DBUS_ERROR_MATCH_RULE_INVALID  )) 
2505     return  DBUS_GERROR_MATCH_RULE_INVALID ;
2506   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_EXEC_FAILED  )) 
2507     return  DBUS_GERROR_SPAWN_EXEC_FAILED ;
2508   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_FORK_FAILED  )) 
2509     return  DBUS_GERROR_SPAWN_FORK_FAILED ;
2510   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_CHILD_EXITED  )) 
2511     return  DBUS_GERROR_SPAWN_CHILD_EXITED ;
2512   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_CHILD_SIGNALED  )) 
2513     return  DBUS_GERROR_SPAWN_CHILD_SIGNALED ;
2514   else if (!strcmp (derr,  DBUS_ERROR_SPAWN_FAILED  )) 
2515     return  DBUS_GERROR_SPAWN_FAILED ;
2516   else if (!strcmp (derr,  DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN  )) 
2517     return  DBUS_GERROR_UNIX_PROCESS_ID_UNKNOWN ;
2518   else if (!strcmp (derr,  DBUS_ERROR_INVALID_SIGNATURE  )) 
2519     return  DBUS_GERROR_INVALID_SIGNATURE ;
2520   else if (!strcmp (derr,  DBUS_ERROR_INVALID_FILE_CONTENT  )) 
2521     return  DBUS_GERROR_INVALID_FILE_CONTENT ;
2522   else if (!strcmp (derr,  DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN  )) 
2523     return  DBUS_GERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN ;
2524   else
2525     return DBUS_GERROR_REMOTE_EXCEPTION;
2526 }
2527
2528 /**
2529  * dbus_set_g_error:
2530  * @gerror: an error
2531  * @derror: a #DBusError
2532  *
2533  * Store the information from a DBus method error return into a
2534  * GError.  For the normal case of an arbitrary remote process,
2535  * the error code will be DBUS_GERROR_REMOTE_EXCEPTION.  Now,
2536  * DBus errors have two components; a message and a "name". 
2537  * The former is an arbitrary (normally American English) string.  
2538  * The second is a string like com.example.FooFailure which 
2539  * programs can use as a conditional source.  Because a GError
2540  * only has one string, we use a hack to encode both values:
2541  *
2542  * &lt;human readable string&gt;&lt;null&gt;&lt;error name&gt;&lt;null&gt;
2543  * 
2544  * You can use the following code to retrieve both values:
2545  * 
2546  * |[const char *msg = error->message;
2547  * size_t len = strlen(msg);
2548  * const char *error_name = msg+len+1;]|
2549  */
2550 void
2551 dbus_set_g_error (GError    **gerror,
2552                   DBusError  *derror)
2553 {
2554   int code;
2555
2556   g_return_if_fail (derror != NULL);
2557   g_return_if_fail (dbus_error_is_set (derror));
2558   g_return_if_fail (gerror == NULL || *gerror == NULL);
2559
2560   code = dbus_error_to_gerror_code (derror->name);
2561   if (code != DBUS_GERROR_REMOTE_EXCEPTION)
2562     g_set_error (gerror, DBUS_GERROR,
2563                  code,
2564                  "%s",
2565                  derror->message);
2566   else
2567     g_set_error (gerror, DBUS_GERROR,
2568                  code,
2569                  "%s%c%s",
2570                  derror->message ? derror->message : "",
2571                  '\0',
2572                  derror->name);
2573 }
2574
2575 static void
2576 dbus_g_error_info_free (gpointer p)
2577 {
2578   DBusGErrorInfo *info;
2579
2580   info = p;
2581
2582   g_free (info->default_iface);
2583   g_free (info);
2584 }
2585
2586 /**
2587  * SECTION:dbus-gobject
2588  * @short_description: Exporting a #GObject remotely
2589  * @see_also: #GObject
2590  * @stability: Stable
2591  *
2592  * FIXME
2593  */
2594
2595 /**
2596  * dbus_glib_global_set_disable_legacy_property_access:
2597  *
2598  * For historical reasons, DBus-GLib will allow read-only
2599  * access to every GObject property of an object exported
2600  * to the bus, regardless of whether or not the property
2601  * is listed in the type info installed with
2602  * dbus_g_object_type_install_info().  (Write access is
2603  * denied however).
2604  *
2605  * If you wish to restrict even read-only access, you
2606  * can call this method to globally change the behavior
2607  * for the entire process.
2608  *
2609  * Since: 0.88
2610  */
2611 void
2612 dbus_glib_global_set_disable_legacy_property_access (void)
2613 {
2614   disable_legacy_property_access = TRUE;
2615 }
2616
2617 /**
2618  * dbus_g_object_type_install_info:
2619  * @object_type: #GType for the object
2620  * @info: introspection data generated by #dbus-glib-tool
2621  *
2622  * Install introspection information about the given object #GType
2623  * sufficient to allow methods on the object to be invoked by name.
2624  * The introspection information is normally generated by
2625  * dbus-glib-tool, then this function is called in the
2626  * class_init() for the object class.
2627  *
2628  * Once introspection information has been installed, instances of the
2629  * object registered with dbus_g_connection_register_g_object() can have
2630  * their methods invoked remotely.
2631  */
2632 void
2633 dbus_g_object_type_install_info (GType                  object_type,
2634                                  const DBusGObjectInfo *info)
2635 {
2636   g_return_if_fail (G_TYPE_IS_CLASSED (object_type) || G_TYPE_IS_INTERFACE (object_type));
2637
2638   _dbus_g_value_types_init ();
2639
2640   g_type_set_qdata (object_type,
2641                     dbus_g_object_type_dbus_metadata_quark (),
2642                     (gpointer) info);
2643 }
2644
2645 /**
2646  * dbus_g_error_domain_register:
2647  * @domain: the #GError domain
2648  * @default_iface: the prefix used for error values, or %NULL
2649  * @code_enum: a #GType for a #GEnum of the error codes
2650  *
2651  * Register a #GError domain and set of codes with D-Bus. When an object
2652  * raises a #GError in the domain @domain from one of its D-Bus methods,
2653  * the D-Bus error name used will be @default_iface, followed by a dot,
2654  * followed by the #GEnumValue.value_nick corresponding to the #GError.code.
2655  * For D-Bus, it's conventional to use an error name (value_nick) that is
2656  * in CamelCase.
2657  *
2658  * (For instance, if a D-Bus method <code>com.example.MyObject.GetThings</code>
2659  * can raise a #GError with domain <code>MY_ERROR</code> and code
2660  * <code>MY_ERROR_NOT_HAPPY</code>, you could call
2661  * <code>dbus_g_error_domain_register (MY_ERROR, "com.example.MyError",
2662  * MY_TYPE_ERROR)</code>, and set up the value_nick for
2663  * <code>MY_ERROR_NOT_HAPPY</code> to be <code>NotHappy</code>,
2664  * resulting in the D-Bus error string
2665  * <code>com.example.MyError.NotHappy</code>.)
2666  *
2667  * If @default_iface is %NULL, the D-Bus interface of the method that failed
2668  * will be used.
2669  *
2670  * (For instance, if the above example had called
2671  * <code>dbus_g_error_domain_register (MY_ERROR, NULL, MY_TYPE_ERROR)</code>
2672  * instead, then the D-Bus error string would be
2673  * <code>com.example.MyObject.NotHappy</code>.)
2674  */
2675 void
2676 dbus_g_error_domain_register (GQuark                domain,
2677                               const char           *default_iface,
2678                               GType                 code_enum)
2679 {
2680   DBusGErrorInfo *info;
2681   
2682   g_return_if_fail (g_quark_to_string (domain) != NULL);
2683   g_return_if_fail (code_enum != G_TYPE_INVALID);
2684   g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
2685
2686   g_static_rw_lock_writer_lock (&globals_lock);
2687
2688   if (error_metadata == NULL)
2689     g_datalist_init (&error_metadata);
2690
2691   info = g_datalist_id_get_data (&error_metadata, domain);
2692
2693   if (info != NULL)
2694     {
2695       g_warning ("Metadata for error domain \"%s\" already registered\n",
2696                  g_quark_to_string (domain));
2697     }
2698   else
2699     {
2700       info = g_new0 (DBusGErrorInfo, 1);
2701       info->default_iface = g_strdup (default_iface);
2702       info->code_enum = code_enum;
2703
2704       g_datalist_id_set_data_full (&error_metadata,
2705                                    domain,
2706                                    info,
2707                                    dbus_g_error_info_free);
2708     }
2709
2710   g_static_rw_lock_writer_unlock (&globals_lock);
2711 }
2712
2713 /* Called when the object is destroyed */
2714 static void
2715 object_export_object_died (gpointer user_data, GObject *dead)
2716 {
2717   ObjectExport *oe = user_data;
2718
2719   g_assert (dead == oe->object);
2720
2721   /* this prevents the weak unref from taking place, which would cause an
2722    * assertion failure since the object has already gone... */
2723   oe->object = NULL;
2724
2725   /* ... while this results in a call to object_registration_unregistered
2726    * for each contained registration */
2727   object_export_unregister_all (oe);
2728
2729   /* We deliberately don't remove the ObjectExport yet, in case the object is
2730    * resurrected and re-registered: if that happens, we wouldn't want to call
2731    * export_signals() again. */
2732 }
2733
2734 /**
2735  * dbus_g_connection_unregister_g_object:
2736  * @connection: the D-BUS connection
2737  * @object: the object
2738  *
2739  * Removes @object from any object paths at which it is exported on
2740  * @connection. Properties, methods, and signals
2741  * of the object can no longer be accessed remotely.
2742  */
2743 void
2744 dbus_g_connection_unregister_g_object (DBusGConnection *connection,
2745                                        GObject *object)
2746 {
2747   ObjectExport *oe;
2748   GSList *registrations;
2749
2750   g_return_if_fail (connection != NULL);
2751   g_return_if_fail (G_IS_OBJECT (object));
2752
2753   oe = g_object_get_data (object, "dbus_glib_object_registrations");
2754
2755   g_return_if_fail (oe != NULL);
2756   g_return_if_fail (oe->registrations != NULL);
2757
2758   /* Copy the list before iterating it: it will be modified in
2759    * object_registration_free() each time an object path is unregistered.
2760    */
2761   for (registrations = g_slist_copy (oe->registrations);
2762       registrations != NULL;
2763       registrations = g_slist_delete_link (registrations, registrations))
2764     {
2765       ObjectRegistration *o = registrations->data;
2766
2767       if (o->connection != connection)
2768         continue;
2769
2770       dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (o->connection),
2771           o->object_path);
2772     }
2773 }
2774
2775 /**
2776  * dbus_g_connection_register_g_object:
2777  * @connection: the D-BUS connection
2778  * @at_path: the path where the object will live (the object's name)
2779  * @object: the object
2780  *
2781  * Registers a #GObject at the given path. Properties, methods, and signals
2782  * of the object can then be accessed remotely. Methods are only available
2783  * if method introspection data has been added to the object's class
2784  * with dbus_g_object_type_install_info().
2785  *
2786  * The registration will be cancelled if either the #DBusConnection or
2787  * the #GObject gets finalized, or if dbus_g_connection_unregister_g_object()
2788  * is used.
2789  *
2790  * Note: If an object is registered multiple times, the first registration
2791  * takes priority for cases such as turning an object into an object path.
2792  */
2793 void
2794 dbus_g_connection_register_g_object (DBusGConnection       *connection,
2795                                      const char            *at_path,
2796                                      GObject               *object)
2797 {
2798   ObjectExport *oe;
2799   GSList *iter;
2800   ObjectRegistration *o;
2801   DBusError error;
2802
2803   g_return_if_fail (connection != NULL);
2804   g_return_if_fail (g_variant_is_object_path (at_path));
2805   g_return_if_fail (G_IS_OBJECT (object));
2806
2807   oe = g_object_get_data (object, "dbus_glib_object_registrations");
2808
2809   if (oe == NULL)
2810     {
2811       GList *info_list = lookup_object_info (object);
2812
2813       if (info_list == NULL)
2814         {
2815           g_warning ("No introspection data registered for object class \"%s\"",
2816                      g_type_name (G_TYPE_FROM_INSTANCE (object)));
2817           return;
2818         }
2819
2820       /* This adds a hook into every signal for the object.  Only do this
2821        * on the first registration, because inside the signal marshaller
2822        * we emit a signal for each registration.
2823        */
2824       export_signals (info_list, object);
2825       g_list_free (info_list);
2826
2827       oe = object_export_new ();
2828       g_object_set_data_full (object, "dbus_glib_object_registrations", oe,
2829           (GDestroyNotify) object_export_free);
2830     }
2831
2832   if (oe->object == NULL)
2833     {
2834       /* Either the ObjectExport is newly-created, or it already existed but
2835        * the object was disposed and resurrected, causing the weak ref to
2836        * fall off */
2837       oe->object = object;
2838       g_object_weak_ref (object, object_export_object_died, oe);
2839     }
2840
2841   for (iter = oe->registrations; iter; iter = iter->next)
2842     {
2843       o = iter->data;
2844
2845       /* Silently ignore duplicate registrations */
2846       if (strcmp (o->object_path, at_path) == 0 && o->connection == connection)
2847         return;
2848     }
2849
2850   o = object_registration_new (connection, at_path, oe);
2851
2852   dbus_error_init (&error);
2853   if (!dbus_connection_try_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
2854                                                  at_path,
2855                                                  &gobject_dbus_vtable,
2856                                                  o,
2857                                                  &error))
2858     {
2859       g_error ("Failed to register GObject with DBusConnection: %s %s",
2860                error.name, error.message);
2861       dbus_error_free (&error);
2862       object_registration_free (o);
2863       return;
2864     }
2865
2866   oe->registrations = g_slist_append (oe->registrations, o);
2867 }
2868
2869 /**
2870  * dbus_g_connection_lookup_g_object:
2871  * @connection: a #DBusGConnection
2872  * @at_path: path
2873  *
2874  * FIXME 
2875  *
2876  * Returns: the object at path @at_path
2877  */
2878 GObject *
2879 dbus_g_connection_lookup_g_object (DBusGConnection       *connection,
2880                                    const char            *at_path)
2881 {
2882   gpointer p;
2883   ObjectRegistration *o;
2884
2885   g_return_val_if_fail (connection != NULL, NULL);
2886   g_return_val_if_fail (g_variant_is_object_path (at_path), NULL);
2887
2888   if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &p))
2889     return NULL;
2890
2891   if (p == NULL)
2892     return NULL;
2893
2894   o = p;
2895
2896   if (o->export->object == NULL)
2897     return NULL;
2898
2899   return G_OBJECT (o->export->object);
2900 }
2901
2902 typedef struct {
2903   GType    rettype;
2904   guint    n_params;
2905   GType   *params;
2906 } DBusGFuncSignature;
2907
2908 static guint
2909 funcsig_hash (gconstpointer key)
2910 {
2911   const DBusGFuncSignature *sig = key;
2912   GType *types;
2913   guint ret;
2914   guint i;
2915
2916   ret = sig->rettype;
2917   types = sig->params;
2918
2919   for (i = 0; i < sig->n_params; i++)
2920     {
2921       ret += (int) (*types);
2922       types++;
2923     }
2924       
2925   return ret;
2926 }
2927
2928 static gboolean
2929 funcsig_equal (gconstpointer aval,
2930                gconstpointer bval)
2931 {
2932   const DBusGFuncSignature *a = aval;
2933   const DBusGFuncSignature *b = bval;
2934   const GType *atypes;
2935   const GType *btypes;
2936   guint i;
2937
2938   if (a->rettype != b->rettype
2939       || a->n_params != b->n_params)
2940     return FALSE;
2941
2942   atypes = a->params;
2943   btypes = b->params;
2944
2945   for (i = 0; i < a->n_params; i++)
2946     {
2947       if (*btypes != *atypes)
2948         return FALSE;
2949       atypes++;
2950       btypes++;
2951     }
2952       
2953   return TRUE;
2954 }
2955
2956 static void
2957 funcsig_free (DBusGFuncSignature *sig)
2958 {
2959   g_free (sig->params);
2960   g_free (sig);
2961 }
2962
2963 GClosureMarshal
2964 _dbus_gobject_lookup_marshaller (GType        rettype,
2965                                  guint        n_params,
2966                                  const GType *param_types)
2967 {
2968   GClosureMarshal ret;
2969   DBusGFuncSignature sig;
2970   GType *params;
2971   guint i;
2972
2973   /* Convert to fundamental types */
2974   rettype = G_TYPE_FUNDAMENTAL (rettype);
2975   params = g_new (GType, n_params);
2976   for (i = 0; i < n_params; i++)
2977     params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
2978
2979   sig.rettype = rettype;
2980   sig.n_params = n_params;
2981   sig.params = params;
2982   
2983   g_static_rw_lock_reader_lock (&globals_lock);
2984
2985   if (marshal_table)
2986     ret = g_hash_table_lookup (marshal_table, &sig);
2987   else
2988     ret = NULL;
2989
2990   g_static_rw_lock_reader_unlock (&globals_lock);
2991
2992   if (ret == NULL)
2993     {
2994       if (rettype == G_TYPE_NONE)
2995         {
2996           if (n_params == 0)
2997             ret = g_cclosure_marshal_VOID__VOID;
2998           else if (n_params == 1)
2999             {
3000               switch (params[0])
3001                 {
3002                 case G_TYPE_BOOLEAN:
3003                   ret = g_cclosure_marshal_VOID__BOOLEAN;
3004                   break;
3005                 case G_TYPE_UCHAR:
3006                   ret = g_cclosure_marshal_VOID__UCHAR;
3007                   break;
3008                 case G_TYPE_INT:
3009                   ret = g_cclosure_marshal_VOID__INT;
3010                   break;
3011                 case G_TYPE_UINT:
3012                   ret = g_cclosure_marshal_VOID__UINT;
3013                   break;
3014                 case G_TYPE_DOUBLE:
3015                   ret = g_cclosure_marshal_VOID__DOUBLE;
3016                   break;
3017                 case G_TYPE_STRING:
3018                   ret = g_cclosure_marshal_VOID__STRING;
3019                   break;
3020                 case G_TYPE_BOXED:
3021                   ret = g_cclosure_marshal_VOID__BOXED;
3022                   break;
3023                 }
3024             }
3025           else if (n_params == 3
3026                    && params[0] == G_TYPE_STRING
3027                    && params[1] == G_TYPE_STRING
3028                    && params[2] == G_TYPE_STRING)
3029             {
3030               ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
3031             }
3032         }
3033     }
3034
3035   g_free (params);
3036   return ret;
3037 }
3038
3039 /**
3040  * dbus_g_object_register_marshaller:
3041  * @marshaller: a GClosureMarshal to be used for invocation
3042  * @rettype: a GType for the return type of the function
3043  * @...: The parameter #GTypes, followed by %G_TYPE_INVALID
3044  *
3045  * Register a #GClosureMarshal to be used for signal invocations,
3046  * giving its return type and a list of parameter types,
3047  * followed by %G_TYPE_INVALID.
3048  *
3049  * This function will not be needed once GLib includes libffi.
3050  */
3051 void
3052 dbus_g_object_register_marshaller (GClosureMarshal  marshaller,
3053                                    GType            rettype,
3054                                    ...)
3055 {
3056   va_list args;
3057   GArray *types;
3058   GType gtype;
3059
3060   va_start (args, rettype);
3061
3062   types = g_array_new (TRUE, TRUE, sizeof (GType));
3063
3064   while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
3065     g_array_append_val (types, gtype);
3066
3067   dbus_g_object_register_marshaller_array (marshaller, rettype,
3068                                            types->len, (GType*) types->data);
3069
3070   g_array_free (types, TRUE);
3071   va_end (args);
3072 }
3073
3074 /**
3075  * dbus_g_object_register_marshaller_array:
3076  * @marshaller: a #GClosureMarshal to be used for invocation
3077  * @rettype: a #GType for the return type of the function
3078  * @n_types: number of function parameters
3079  * @types: a C array of GTypes values
3080  *
3081  * Register a #GClosureMarshal to be used for signal invocations.
3082  * @see_also dbus_g_object_register_marshaller()
3083  */
3084 void
3085 dbus_g_object_register_marshaller_array (GClosureMarshal  marshaller,
3086                                          GType            rettype,
3087                                          guint            n_types,
3088                                          const GType*     types)
3089 {
3090   DBusGFuncSignature *sig;
3091   guint i;
3092
3093   g_static_rw_lock_writer_lock (&globals_lock);
3094
3095   if (marshal_table == NULL)
3096     marshal_table = g_hash_table_new_full (funcsig_hash,
3097                                            funcsig_equal,
3098                                            (GDestroyNotify) funcsig_free,
3099                                            NULL);
3100   sig = g_new0 (DBusGFuncSignature, 1);
3101   sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
3102   sig->n_params = n_types;
3103   sig->params = g_new (GType, n_types);
3104   for (i = 0; i < n_types; i++)
3105     sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
3106
3107   g_hash_table_insert (marshal_table, sig, marshaller);
3108
3109   g_static_rw_lock_writer_unlock (&globals_lock);
3110 }
3111
3112 /**
3113  * dbus_g_method_get_sender:
3114  * @context: the method context
3115  *
3116  * Get the sender of a message so we can send a
3117  * "reply" later (i.e. send a message directly
3118  * to a service which invoked the method at a
3119  * later time).
3120  *
3121  * Returns: the unique name of the sender. It
3122  * is up to the caller to free the returned string.
3123  */
3124 gchar *
3125 dbus_g_method_get_sender (DBusGMethodInvocation *context)
3126 {
3127   const gchar *sender;
3128
3129   g_return_val_if_fail (context != NULL, NULL);
3130
3131   sender = dbus_message_get_sender (dbus_g_message_get_message (context->message));
3132   return g_strdup (sender);
3133 }
3134
3135 /**
3136  * dbus_g_method_get_reply:
3137  * @context: the method context
3138  *
3139  * Get the reply message to append reply values
3140  * Used as a sidedoor when you can't generate dbus values
3141  * of the correct type due to glib binding limitations
3142  *
3143  * Returns: a #DBusMessage with the reply
3144  */
3145 DBusMessage *
3146 dbus_g_method_get_reply (DBusGMethodInvocation *context)
3147 {
3148   g_return_val_if_fail (context != NULL, NULL);
3149
3150   return reply_or_die (dbus_g_message_get_message (context->message));
3151 }
3152
3153 /**
3154  * dbus_g_method_send_reply:
3155  * @context: the method context
3156  * @reply: the reply message, will be unreffed
3157  *
3158  * Send a manually created reply message.
3159  *
3160  * Used as a sidedoor when you can't generate dbus values
3161  * of the correct type due to glib binding limitations
3162  */
3163 void
3164 dbus_g_method_send_reply (DBusGMethodInvocation *context, DBusMessage *reply)
3165 {
3166   g_return_if_fail (context != NULL);
3167   g_return_if_fail (reply != NULL);
3168
3169   connection_send_or_die (dbus_g_connection_get_connection (context->connection),
3170       reply);
3171   dbus_message_unref (reply);
3172
3173   dbus_g_connection_unref (context->connection);
3174   dbus_g_message_unref (context->message);
3175   g_free (context);
3176 }
3177
3178
3179 /**
3180  * dbus_g_method_return:
3181  * @context: the method context
3182  * @...: zero or more values to return from the method, with their number
3183  *    and types given by its #DBusGObjectInfo
3184  *
3185  * Send a return message for a given method invocation, with arguments.
3186  * This function also frees the sending context.
3187  */
3188 void
3189 dbus_g_method_return (DBusGMethodInvocation *context, ...)
3190 {
3191   DBusMessage *reply;
3192   DBusMessageIter iter;
3193   va_list args;
3194   char *out_sig;
3195   GArray *argsig;
3196   guint i;
3197
3198   g_return_if_fail (context != NULL);
3199
3200   /* This field was initialized inside invoke_object_method; we
3201    * carry it over through the async invocation to here.
3202    */
3203   if (!context->send_reply)
3204     goto out;
3205
3206   reply = dbus_g_method_get_reply (context);
3207   out_sig = method_output_signature_from_object_info (context->object, context->method);
3208   argsig = _dbus_gtypes_from_arg_signature (out_sig, FALSE);
3209
3210   dbus_message_iter_init_append (reply, &iter);
3211
3212   va_start (args, context);
3213   for (i = 0; i < argsig->len; i++)
3214     {
3215       GValue value = {0,};
3216       char *error;
3217       g_value_init (&value, g_array_index (argsig, GType, i));
3218       error = NULL;
3219       G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
3220       if (error)
3221         {
3222           g_warning("%s", error);
3223           g_free (error);
3224         }
3225       else
3226         {
3227           if (!_dbus_gvalue_marshal (&iter, &value))
3228             g_warning ("failed to marshal parameter %d for method %s",
3229                        i, dbus_message_get_member (
3230                          dbus_g_message_get_message (context->message)));
3231         }
3232     }
3233   va_end (args);
3234
3235   connection_send_or_die (dbus_g_connection_get_connection (context->connection),
3236       reply);
3237   dbus_message_unref (reply);
3238
3239   g_free (out_sig);
3240   g_array_free (argsig, TRUE);
3241
3242 out:
3243   dbus_g_connection_unref (context->connection);
3244   dbus_g_message_unref (context->message);
3245   g_free (context);
3246 }
3247
3248 /**
3249  * dbus_g_method_return_error:
3250  * @context: the method context
3251  * @error: the error to send
3252  *
3253  * Send a error message for a given method invocation.
3254  * This function also frees the sending context.
3255  */
3256 void
3257 dbus_g_method_return_error (DBusGMethodInvocation *context, const GError *error)
3258 {
3259   DBusMessage *reply;
3260
3261   g_return_if_fail (context != NULL);
3262   g_return_if_fail (error != NULL);
3263
3264   /* See comment in dbus_g_method_return */
3265   if (!context->send_reply)
3266     goto out;
3267
3268   reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
3269   connection_send_or_die (
3270       dbus_g_connection_get_connection (context->connection), reply);
3271   dbus_message_unref (reply);
3272
3273 out:
3274   dbus_g_connection_unref (context->connection);
3275   dbus_g_message_unref (context->message);
3276   g_free (context);
3277 }
3278
3279 const char *
3280 _dbus_gobject_get_path (GObject *obj)
3281 {
3282   ObjectExport *oe;
3283   ObjectRegistration *o;
3284
3285   oe = g_object_get_data (obj, "dbus_glib_object_registrations");
3286
3287   if (oe == NULL || oe->registrations == NULL)
3288     return NULL;
3289
3290   /* First one to have been registered wins */
3291   o = oe->registrations->data;
3292
3293   return o->object_path;
3294 }
3295
3296 #ifdef DBUS_BUILD_TESTS
3297 #include <stdlib.h>
3298
3299 static void
3300 _dummy_function (void)
3301 {
3302 }
3303
3304 /* Data structures copied from one generated by current dbus-binding-tool;
3305  * we need to support this layout forever
3306  */
3307 static const DBusGMethodInfo dbus_glib_internal_test_methods[] = {
3308   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 0 },
3309   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 49 },
3310   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 117 },
3311   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 191 },
3312   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 270 },
3313   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 320 },
3314   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 391 },
3315   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 495 },
3316   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 623 },
3317   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 693 },
3318   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 765 },
3319   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 838 },
3320   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 911 },
3321   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 988 },
3322   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1064 },
3323   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1140 },
3324   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1204 },
3325   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1278 },
3326   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1347 },
3327   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1408 },
3328   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1460 },
3329   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1533 },
3330   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1588 },
3331   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1647 },
3332   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1730 },
3333   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1784 },
3334   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1833 },
3335   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1895 },
3336   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1947 },
3337   { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1999 },
3338 };
3339
3340 const DBusGObjectInfo dbus_glib_internal_test_object_info = {
3341   0,
3342   dbus_glib_internal_test_methods,
3343   30,
3344 "org.freedesktop.DBus.Tests.MyObject\0DoNothing\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Increment\0S\0x\0I\0u\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementRetval\0S\0x\0I\0u\0arg1\0O\0F\0R\0u\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementRetvalError\0S\0x\0I\0u\0arg1\0O\0F\0E\0u\0\0org.freedesktop.DBus.Tests.MyObject\0ThrowError\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Uppercase\0S\0arg0\0I\0s\0arg1\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0ManyArgs\0S\0x\0I\0u\0str\0I\0s\0trouble\0I\0d\0d_ret\0O\0F\0N\0d\0str_ret\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0ManyReturn\0S\0arg0\0O\0F\0N\0u\0arg1\0O\0F\0N\0s\0arg2\0O\0F\0N\0i\0arg3\0O\0F\0N\0u\0arg4\0O\0F\0N\0u\0arg5\0O\0C\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0Stringify\0S\0val\0I\0v\0arg1\0O\0F\0N\0s\0\0org.freedesktop.DBus.Tests.MyObject\0Unstringify\0S\0val\0I\0s\0arg1\0O\0F\0N\0v\0\0org.freedesktop.DBus.Tests.MyObject\0Recursive1\0S\0arg0\0I\0au\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0Recursive2\0S\0arg0\0I\0u\0arg1\0O\0F\0N\0au\0\0org.freedesktop.DBus.Tests.MyObject\0ManyUppercase\0S\0arg0\0I\0as\0arg1\0O\0F\0N\0as\0\0org.freedesktop.DBus.Tests.MyObject\0StrHashLen\0S\0arg0\0I\0a{ss}\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0SendCar\0S\0arg0\0I\0(suv)\0arg1\0O\0F\0N\0(uo)\0\0org.freedesktop.DBus.Tests.MyObject\0GetHash\0S\0arg0\0O\0F\0N\0a{ss}\0\0org.freedesktop.DBus.Tests.MyObject\0RecArrays\0S\0val\0I\0aas\0arg1\0O\0F\0N\0aau\0\0org.freedesktop.DBus.Tests.MyObject\0Objpath\0S\0arg0\0I\0o\0arg1\0O\0C\0N\0o\0\0org.freedesktop.DBus.Tests.MyObject\0GetObjs\0S\0arg0\0O\0F\0N\0ao\0\0org.freedesktop.DBus.Tests.MyObject\0IncrementVal\0S\0\0org.freedesktop.DBus.Tests.MyObject\0AsyncIncrement\0A\0x\0I\0u\0arg1\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0AsyncThrowError\0A\0\0org.freedesktop.DBus.Tests.MyObject\0GetVal\0S\0arg0\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.MyObject\0ManyStringify\0S\0arg0\0I\0a{sv}\0arg1\0O\0F\0N\0a{sv}\0\0org.freedesktop.DBus.Tests.MyObject\0EmitFrobnicate\0S\0\0org.freedesktop.DBus.Tests.MyObject\0Terminate\0S\0\0org.freedesktop.DBus.Tests.FooObject\0GetValue\0S\0arg0\0O\0F\0N\0u\0\0org.freedesktop.DBus.Tests.FooObject\0EmitSignals\0S\0\0org.freedesktop.DBus.Tests.FooObject\0EmitSignal2\0S\0\0org.freedesktop.DBus.Tests.FooObject\0Terminate\0S\0\0\0",
3345 "org.freedesktop.DBus.Tests.MyObject\0Frobnicate\0org.freedesktop.DBus.Tests.FooObject\0Sig0\0org.freedesktop.DBus.Tests.FooObject\0Sig1\0org.freedesktop.DBus.Tests.FooObject\0Sig2\0\0",
3346 "\0"
3347 };
3348
3349
3350 /*
3351  * Unit test for GLib GObject integration ("skeletons")
3352  * Returns: %TRUE on success.
3353  */
3354 gboolean
3355 _dbus_gobject_test (const char *test_data_dir)
3356 {
3357   int i;
3358   const char *arg;
3359   const char *arg_name;
3360   gboolean arg_in;
3361   gboolean constval;
3362   RetvalType retval;
3363   const char *arg_signature;
3364   const char *sigdata;
3365   const char *iface;
3366   const char *signame;
3367   
3368   static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
3369     { "SetFoo", "set_foo" },
3370     { "Foo", "foo" },
3371     { "GetFooBar", "get_foo_bar" },
3372     { "Hello", "hello" }
3373     
3374     /* Impossible-to-handle cases */
3375     /* { "FrobateUIHandler", "frobate_ui_handler" } */
3376   };
3377
3378   /* Test lookup in our hardcoded object info; if these tests fail
3379    * then it likely means you changed the generated object info in an
3380    * incompatible way and broke the lookup functions.  In that case
3381    * you need to bump the version and use a new structure instead. */
3382   /* DoNothing */
3383   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
3384                                           &(dbus_glib_internal_test_methods[0]));
3385   g_assert (*arg == '\0');
3386
3387   /* Increment */
3388   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
3389                                           &(dbus_glib_internal_test_methods[1]));
3390   g_assert (*arg != '\0');
3391   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3392   g_assert (!strcmp (arg_name, "x"));
3393   g_assert (arg_in == TRUE);
3394   g_assert (!strcmp (arg_signature, "u"));
3395   g_assert (*arg != '\0');
3396   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3397   g_assert (arg_in == FALSE);
3398   g_assert (retval == RETVAL_NONE);
3399   g_assert (!strcmp (arg_signature, "u"));
3400   g_assert (*arg == '\0');
3401
3402   /* IncrementRetval */
3403   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
3404                                           &(dbus_glib_internal_test_methods[2]));
3405   g_assert (*arg != '\0');
3406   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3407   g_assert (!strcmp (arg_name, "x"));
3408   g_assert (arg_in == TRUE);
3409   g_assert (!strcmp (arg_signature, "u"));
3410   g_assert (*arg != '\0');
3411   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3412   g_assert (retval == RETVAL_NOERROR);
3413   g_assert (arg_in == FALSE);
3414   g_assert (!strcmp (arg_signature, "u"));
3415   g_assert (*arg == '\0');
3416
3417   /* IncrementRetvalError */
3418   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
3419                                           &(dbus_glib_internal_test_methods[3]));
3420   g_assert (*arg != '\0');
3421   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3422   g_assert (!strcmp (arg_name, "x"));
3423   g_assert (arg_in == TRUE);
3424   g_assert (!strcmp (arg_signature, "u"));
3425   g_assert (*arg != '\0');
3426   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3427   g_assert (retval == RETVAL_ERROR);
3428   g_assert (arg_in == FALSE);
3429   g_assert (!strcmp (arg_signature, "u"));
3430   g_assert (*arg == '\0');
3431   
3432   /* Stringify */
3433   arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
3434                                           &(dbus_glib_internal_test_methods[8]));
3435   g_assert (*arg != '\0');
3436   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3437   g_assert (!strcmp (arg_name, "val"));
3438   g_assert (arg_in == TRUE);
3439   g_assert (!strcmp (arg_signature, "v"));
3440   g_assert (*arg != '\0');
3441   arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
3442   g_assert (retval == RETVAL_NONE);
3443   g_assert (arg_in == FALSE);
3444   g_assert (!strcmp (arg_signature, "s"));
3445   g_assert (*arg == '\0');
3446
3447   sigdata = dbus_glib_internal_test_object_info.exported_signals;
3448   g_assert (*sigdata != '\0');
3449   sigdata = signal_iterate (sigdata, &iface, &signame);
3450   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
3451   g_assert (!strcmp (signame, "Frobnicate"));
3452   g_assert (*sigdata != '\0');
3453   sigdata = signal_iterate (sigdata, &iface, &signame);
3454   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
3455   g_assert (!strcmp (signame, "Sig0"));
3456   g_assert (*sigdata != '\0');
3457   sigdata = signal_iterate (sigdata, &iface, &signame);
3458   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
3459   g_assert (!strcmp (signame, "Sig1"));
3460   g_assert (*sigdata != '\0');
3461   sigdata = signal_iterate (sigdata, &iface, &signame);
3462   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
3463   g_assert (!strcmp (signame, "Sig2"));
3464   g_assert (*sigdata == '\0');
3465
3466
3467   i = 0;
3468   while (i < (int) G_N_ELEMENTS (name_pairs))
3469     {
3470       char *uscore;
3471       char *wincaps;
3472
3473       uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
3474       wincaps = uscore_to_wincaps (name_pairs[i].uscore);
3475
3476       if (strcmp (uscore, name_pairs[i].uscore) != 0)
3477         {
3478           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
3479                       name_pairs[i].wincaps, name_pairs[i].uscore,
3480                       uscore);
3481           exit (1);
3482         }
3483       
3484       if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
3485         {
3486           g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
3487                       name_pairs[i].uscore, name_pairs[i].wincaps,
3488                       wincaps);
3489           exit (1);
3490         }
3491       
3492       g_free (uscore);
3493       g_free (wincaps);
3494
3495       ++i;
3496     }
3497   
3498   return TRUE;
3499 }
3500
3501 #endif /* DBUS_BUILD_TESTS */