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