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 * <human readable string><null><error name><null>
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