00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <config.h>
00026 #include <gobject/gvaluecollector.h>
00027 #include <dbus/dbus-glib.h>
00028 #include <dbus/dbus-glib-lowlevel.h>
00029 #include "dbus-gtest.h"
00030 #include "dbus-gutils.h"
00031 #include "dbus-gobject.h"
00032 #include "dbus-gsignature.h"
00033 #include "dbus-gvalue.h"
00034 #include "dbus-gmarshal.h"
00035 #include "dbus-gvalue-utils.h"
00036 #include <string.h>
00037
00043 typedef struct
00044 {
00045 char *default_iface;
00046 GType code_enum;
00047 } DBusGErrorInfo;
00048
00049 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
00050 static GHashTable *marshal_table = NULL;
00051 static GData *error_metadata = NULL;
00052
00053 static char*
00054 uscore_to_wincaps (const char *uscore)
00055 {
00056 const char *p;
00057 GString *str;
00058 gboolean last_was_uscore;
00059
00060 last_was_uscore = TRUE;
00061
00062 str = g_string_new (NULL);
00063 p = uscore;
00064 while (*p)
00065 {
00066 if (*p == '-' || *p == '_')
00067 {
00068 last_was_uscore = TRUE;
00069 }
00070 else
00071 {
00072 if (last_was_uscore)
00073 {
00074 g_string_append_c (str, g_ascii_toupper (*p));
00075 last_was_uscore = FALSE;
00076 }
00077 else
00078 g_string_append_c (str, *p);
00079 }
00080 ++p;
00081 }
00082
00083 return g_string_free (str, FALSE);
00084 }
00085
00086 static const char *
00087 string_table_next (const char *table)
00088 {
00089 return (table + (strlen (table) + 1));
00090 }
00091
00092 static const char *
00093 string_table_lookup (const char *table, int index)
00094 {
00095 const char *ret;
00096
00097 ret = table;
00098
00099 while (index--)
00100 ret = string_table_next (ret);
00101
00102 return ret;
00103 }
00104
00105 static const char *
00106 get_method_data (const DBusGObjectInfo *object,
00107 const DBusGMethodInfo *method)
00108 {
00109 return object->data + method->data_offset;
00110 }
00111
00112 static char *
00113 object_error_domain_prefix_from_object_info (const DBusGObjectInfo *info)
00114 {
00115
00116 return NULL;
00117 }
00118
00119 static char *
00120 object_error_code_from_object_info (const DBusGObjectInfo *info, GQuark domain, gint code)
00121 {
00122
00123 return NULL;
00124 }
00125
00126 static const char *
00127 method_interface_from_object_info (const DBusGObjectInfo *object,
00128 const DBusGMethodInfo *method)
00129 {
00130 return string_table_lookup (get_method_data (object, method), 0);
00131 }
00132
00133 static const char *
00134 method_name_from_object_info (const DBusGObjectInfo *object,
00135 const DBusGMethodInfo *method)
00136 {
00137 return string_table_lookup (get_method_data (object, method), 1);
00138 }
00139
00140 static const char *
00141 method_arg_info_from_object_info (const DBusGObjectInfo *object,
00142 const DBusGMethodInfo *method)
00143 {
00144 return string_table_lookup (get_method_data (object, method), 3);
00145 }
00146
00147 typedef enum
00148 {
00149 RETVAL_NONE,
00150 RETVAL_NOERROR,
00151 RETVAL_ERROR
00152 } RetvalType;
00153
00154 static const char *
00155 arg_iterate (const char *data,
00156 const char **name,
00157 gboolean *in,
00158 gboolean *constval,
00159 RetvalType *retval,
00160 const char **type)
00161 {
00162 gboolean inarg;
00163
00164 if (name)
00165 *name = data;
00166
00167 data = string_table_next (data);
00168 switch (*data)
00169 {
00170 case 'I':
00171 inarg = TRUE;
00172 break;
00173 case 'O':
00174 inarg = FALSE;
00175 break;
00176 default:
00177 g_warning ("invalid arg direction '%c'", *data);
00178 inarg = FALSE;
00179 break;
00180 }
00181 if (in)
00182 *in = inarg;
00183
00184 if (!inarg)
00185 {
00186 data = string_table_next (data);
00187 switch (*data)
00188 {
00189 case 'F':
00190 if (constval)
00191 *constval = FALSE;
00192 break;
00193 case 'C':
00194 if (constval)
00195 *constval = TRUE;
00196 break;
00197 default:
00198 g_warning ("invalid arg const value '%c'", *data);
00199 break;
00200 }
00201 data = string_table_next (data);
00202 switch (*data)
00203 {
00204 case 'N':
00205 if (retval)
00206 *retval = RETVAL_NONE;
00207 break;
00208 case 'E':
00209 if (retval)
00210 *retval = RETVAL_ERROR;
00211 break;
00212 case 'R':
00213 if (retval)
00214 *retval = RETVAL_NOERROR;
00215 break;
00216 default:
00217 g_warning ("invalid arg ret value '%c'", *data);
00218 break;
00219 }
00220 }
00221 else
00222 {
00223 if (constval)
00224 *constval = FALSE;
00225 if (retval)
00226 *retval = FALSE;
00227 }
00228
00229 data = string_table_next (data);
00230 if (type)
00231 *type = data;
00232
00233 return string_table_next (data);
00234 }
00235
00236 static char *
00237 method_dir_signature_from_object_info (const DBusGObjectInfo *object,
00238 const DBusGMethodInfo *method,
00239 gboolean in)
00240 {
00241 const char *arg;
00242 GString *ret;
00243
00244 arg = method_arg_info_from_object_info (object, method);
00245
00246 ret = g_string_new (NULL);
00247
00248 while (*arg)
00249 {
00250 const char *name;
00251 gboolean arg_in;
00252 const char *type;
00253
00254 arg = arg_iterate (arg, &name, &arg_in, NULL, NULL, &type);
00255
00256 if (arg_in == in)
00257 g_string_append (ret, type);
00258 }
00259
00260 return g_string_free (ret, FALSE);
00261 }
00262
00263 static char *
00264 method_input_signature_from_object_info (const DBusGObjectInfo *object,
00265 const DBusGMethodInfo *method)
00266 {
00267 return method_dir_signature_from_object_info (object, method, TRUE);
00268 }
00269
00270 static char *
00271 method_output_signature_from_object_info (const DBusGObjectInfo *object,
00272 const DBusGMethodInfo *method)
00273 {
00274 return method_dir_signature_from_object_info (object, method, FALSE);
00275 }
00276
00277 static const char *
00278 propsig_iterate (const char *data, const char **iface, const char **name)
00279 {
00280 *iface = data;
00281
00282 data = string_table_next (data);
00283 *name = data;
00284
00285 return string_table_next (data);
00286 }
00287
00288 static GQuark
00289 dbus_g_object_type_dbus_metadata_quark (void)
00290 {
00291 static GQuark quark;
00292
00293 if (!quark)
00294 quark = g_quark_from_static_string ("DBusGObjectTypeDBusMetadataQuark");
00295 return quark;
00296 }
00297
00298 static const DBusGObjectInfo *
00299 lookup_object_info (GObject *object)
00300 {
00301 const DBusGObjectInfo *ret;
00302 GType classtype;
00303
00304 ret = NULL;
00305
00306 for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
00307 {
00308 const DBusGObjectInfo *info;
00309
00310 info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ());
00311
00312 if (info != NULL && info->format_version >= 0)
00313 {
00314 ret = info;
00315 break;
00316 }
00317 }
00318
00319 return ret;
00320 }
00321
00322 static void
00323 gobject_unregister_function (DBusConnection *connection,
00324 void *user_data)
00325 {
00326 GObject *object;
00327
00328 object = G_OBJECT (user_data);
00329
00330
00331
00332 }
00333
00334 typedef struct
00335 {
00336 GString *xml;
00337 GType gtype;
00338 const DBusGObjectInfo *object_info;
00339 } DBusGLibWriteIterfaceData;
00340
00341 typedef struct
00342 {
00343 GSList *methods;
00344 GSList *signals;
00345 GSList *properties;
00346 } DBusGLibWriteInterfaceValues;
00347
00348 static void
00349 write_interface (gpointer key, gpointer val, gpointer user_data)
00350 {
00351 const char *name;
00352 GSList *methods;
00353 GSList *signals;
00354 GSList *properties;
00355 GString *xml;
00356 const DBusGObjectInfo *object_info;
00357 DBusGLibWriteIterfaceData *data;
00358 DBusGLibWriteInterfaceValues *values;
00359
00360 name = key;
00361
00362 values = val;
00363 methods = values->methods;
00364 signals = values->signals;
00365 properties = values->properties;
00366
00367 data = user_data;
00368 xml = data->xml;
00369 object_info = data->object_info;
00370
00371 g_string_append_printf (xml, " <interface name=\"%s\">\n", name);
00372
00373
00374 for (; methods; methods = methods->next)
00375 {
00376 DBusGMethodInfo *method;
00377 const char *args;
00378 method = methods->data;
00379
00380 g_string_append_printf (xml, " <method name=\"%s\">\n",
00381 method_name_from_object_info (object_info, method));
00382
00383 args = method_arg_info_from_object_info (object_info, method);
00384
00385 while (*args)
00386 {
00387 const char *name;
00388 gboolean arg_in;
00389 const char *type;
00390
00391 args = arg_iterate (args, &name, &arg_in, NULL, NULL, &type);
00392
00393
00394 g_string_append_printf (xml, " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n",
00395 name, type, arg_in ? "in" : "out");
00396
00397 }
00398 g_string_append (xml, " </method>\n");
00399
00400 }
00401 g_slist_free (values->methods);
00402
00403 for (; signals; signals = signals->next)
00404 {
00405 guint id;
00406 guint arg;
00407 const char *signame;
00408 GSignalQuery query;
00409 char *s;
00410
00411 signame = signals->data;
00412
00413 s = _dbus_gutils_wincaps_to_uscore (signame);
00414
00415 id = g_signal_lookup (s, data->gtype);
00416 g_assert (id != 0);
00417
00418 g_signal_query (id, &query);
00419 g_assert (query.return_type == G_TYPE_NONE);
00420
00421 g_string_append_printf (xml, " <signal name=\"%s\">\n", signame);
00422
00423 for (arg = 0; arg < query.n_params; arg++)
00424 {
00425 char *dbus_type = _dbus_gtype_to_signature (query.param_types[arg]);
00426
00427 g_assert (dbus_type != NULL);
00428
00429 g_string_append (xml, " <arg type=\"");
00430 g_string_append (xml, dbus_type);
00431 g_string_append (xml, "\"/>\n");
00432 g_free (dbus_type);
00433 }
00434
00435 g_string_append (xml, " </signal>\n");
00436 g_free (s);
00437 }
00438 g_slist_free (values->signals);
00439
00440 for (; properties; properties = properties->next)
00441 {
00442 const char *propname;
00443 GParamSpec *spec;
00444 char *dbus_type;
00445 gboolean can_set;
00446 gboolean can_get;
00447 char *s;
00448
00449 propname = properties->data;
00450
00451 s = _dbus_gutils_wincaps_to_uscore (spec->name);
00452
00453 spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
00454 g_assert (spec != NULL);
00455 g_free (s);
00456
00457 dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
00458 g_assert (dbus_type != NULL);
00459
00460 can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
00461 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
00462
00463 can_get = (spec->flags & G_PARAM_READABLE) != 0;
00464
00465 if (can_set || can_get)
00466 {
00467 g_string_append_printf (xml, " <property name=\"%s\" ", propname);
00468 g_string_append (xml, "type=\"");
00469 g_string_append (xml, dbus_type);
00470 g_string_append (xml, "\" access=\"");
00471
00472 if (can_set && can_get)
00473 g_string_append (xml, "readwrite");
00474 else if (can_get)
00475 g_string_append (xml, "read");
00476 else
00477 {
00478 g_assert (can_set);
00479 g_string_append (xml, "write");
00480 }
00481
00482 g_string_append (xml, "\"/>\n");
00483 }
00484
00485 g_free (dbus_type);
00486 g_free (s);
00487
00488 g_string_append (xml, " </property>\n");
00489 }
00490 g_slist_free (values->properties);
00491
00492 g_free (values);
00493 g_string_append (xml, " </interface>\n");
00494 }
00495
00496 static DBusGLibWriteInterfaceValues *
00497 lookup_values (GHashTable *interfaces, const char *method_interface)
00498 {
00499 DBusGLibWriteInterfaceValues *values;
00500 if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
00501 {
00502 values = g_new0 (DBusGLibWriteInterfaceValues, 1);
00503 g_hash_table_insert (interfaces, (gpointer) method_interface, values);
00504 }
00505 return values;
00506 }
00507
00508 static void
00509 introspect_interfaces (GObject *object, GString *xml)
00510 {
00511 const DBusGObjectInfo *info;
00512 DBusGLibWriteIterfaceData data;
00513 int i;
00514 GHashTable *interfaces;
00515 DBusGLibWriteInterfaceValues *values;
00516 const char *propsig;
00517
00518 info = lookup_object_info (object);
00519
00520 g_assert (info != NULL);
00521
00522
00523 interfaces = g_hash_table_new (g_str_hash, g_str_equal);
00524 for (i = 0; i < info->n_method_infos; i++)
00525 {
00526 const char *method_name;
00527 const char *method_interface;
00528 const char *method_args;
00529 const DBusGMethodInfo *method;
00530
00531 method = &(info->method_infos[i]);
00532
00533 method_interface = method_interface_from_object_info (info, method);
00534 method_name = method_name_from_object_info (info, method);
00535 method_args = method_arg_info_from_object_info (info, method);
00536
00537 values = lookup_values (interfaces, method_interface);
00538 values->methods = g_slist_prepend (values->methods, (gpointer) method);
00539 }
00540
00541 propsig = info->exported_signals;
00542 while (*propsig)
00543 {
00544 const char *iface;
00545 const char *signame;
00546
00547 propsig = propsig_iterate (propsig, &iface, &signame);
00548
00549 values = lookup_values (interfaces, iface);
00550 values->signals = g_slist_prepend (values->signals, (gpointer) signame);
00551 }
00552
00553 propsig = info->exported_properties;
00554 while (*propsig)
00555 {
00556 const char *iface;
00557 const char *propname;
00558
00559 propsig = propsig_iterate (propsig, &iface, &propname);
00560
00561 values = lookup_values (interfaces, iface);
00562 values->properties = g_slist_prepend (values->properties, (gpointer) propname);
00563 }
00564
00565 memset (&data, 0, sizeof (data));
00566 data.xml = xml;
00567 data.gtype = G_TYPE_FROM_INSTANCE (object);
00568 data.object_info = info;
00569 g_hash_table_foreach (interfaces, write_interface, &data);
00570
00571 g_hash_table_destroy (interfaces);
00572 }
00573
00574 static DBusHandlerResult
00575 handle_introspect (DBusConnection *connection,
00576 DBusMessage *message,
00577 GObject *object)
00578 {
00579 GString *xml;
00580 unsigned int i;
00581 DBusMessage *ret;
00582 char **children;
00583
00584 if (!dbus_connection_list_registered (connection,
00585 dbus_message_get_path (message),
00586 &children))
00587 g_error ("Out of memory");
00588
00589 xml = g_string_new (NULL);
00590
00591 g_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
00592
00593 g_string_append (xml, "<node>\n");
00594
00595
00596 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE);
00597 g_string_append (xml, " <method name=\"Introspect\">\n");
00598 g_string_append_printf (xml, " <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00599 g_string_append (xml, " </method>\n");
00600 g_string_append (xml, " </interface>\n");
00601
00602
00603 g_string_append_printf (xml, " <interface name=\"%s\">\n", DBUS_INTERFACE_PROPERTIES);
00604 g_string_append (xml, " <method name=\"Get\">\n");
00605 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00606 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00607 g_string_append_printf (xml, " <arg name=\"value\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00608 g_string_append (xml, " </method>\n");
00609 g_string_append (xml, " <method name=\"Set\">\n");
00610 g_string_append_printf (xml, " <arg name=\"interface\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00611 g_string_append_printf (xml, " <arg name=\"propname\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING);
00612 g_string_append_printf (xml, " <arg name=\"value\" direction=\"in\" type=\"%s\"/>\n", DBUS_TYPE_VARIANT_AS_STRING);
00613 g_string_append (xml, " </method>\n");
00614 g_string_append (xml, " </interface>\n");
00615
00616 introspect_interfaces (object, xml);
00617
00618
00619 for (i = 0; children[i]; i++)
00620 g_string_append_printf (xml, " <node name=\"%s\"/>\n",
00621 children[i]);
00622
00623
00624 g_string_append (xml, "</node>\n");
00625
00626 ret = dbus_message_new_method_return (message);
00627 if (ret == NULL)
00628 g_error ("Out of memory");
00629
00630 dbus_message_append_args (ret,
00631 DBUS_TYPE_STRING, &xml->str,
00632 DBUS_TYPE_INVALID);
00633
00634 dbus_connection_send (connection, ret, NULL);
00635 dbus_message_unref (ret);
00636
00637 g_string_free (xml, TRUE);
00638
00639 dbus_free_string_array (children);
00640
00641 return DBUS_HANDLER_RESULT_HANDLED;
00642 }
00643
00644 static DBusMessage*
00645 set_object_property (DBusConnection *connection,
00646 DBusMessage *message,
00647 DBusMessageIter *iter,
00648 GObject *object,
00649 GParamSpec *pspec)
00650 {
00651 GValue value = { 0, };
00652 DBusMessage *ret;
00653 DBusMessageIter sub;
00654 DBusGValueMarshalCtx context;
00655
00656 dbus_message_iter_recurse (iter, &sub);
00657
00658 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00659 context.proxy = NULL;
00660
00661 g_value_init (&value, pspec->value_type);
00662 if (_dbus_gvalue_demarshal (&context, &sub, &value, NULL))
00663 {
00664 g_object_set_property (object,
00665 pspec->name,
00666 &value);
00667
00668 g_value_unset (&value);
00669
00670 ret = dbus_message_new_method_return (message);
00671 if (ret == NULL)
00672 g_error ("out of memory");
00673 }
00674 else
00675 {
00676 ret = dbus_message_new_error (message,
00677 DBUS_ERROR_INVALID_ARGS,
00678 "Argument's D-BUS type can't be converted to a GType");
00679 if (ret == NULL)
00680 g_error ("out of memory");
00681 }
00682
00683 return ret;
00684 }
00685
00686 static DBusMessage*
00687 get_object_property (DBusConnection *connection,
00688 DBusMessage *message,
00689 GObject *object,
00690 GParamSpec *pspec)
00691 {
00692 GType value_type;
00693 GValue value = {0, };
00694 DBusMessage *ret;
00695 DBusMessageIter iter;
00696
00697 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
00698
00699 ret = dbus_message_new_method_return (message);
00700 if (ret == NULL)
00701 g_error ("out of memory");
00702
00703 g_value_init (&value, value_type);
00704 g_object_get_property (object, pspec->name, &value);
00705
00706 value_type = G_VALUE_TYPE (&value);
00707
00708 dbus_message_iter_init_append (message, &iter);
00709
00710 if (!_dbus_gvalue_marshal (&iter, &value))
00711 {
00712 dbus_message_unref (ret);
00713 ret = dbus_message_new_error (message,
00714 DBUS_ERROR_UNKNOWN_METHOD,
00715 "Can't convert GType of object property to a D-BUS type");
00716 }
00717
00718 return ret;
00719 }
00720
00721 static gboolean
00722 lookup_object_and_method (GObject *object,
00723 DBusMessage *message,
00724 const DBusGObjectInfo **object_ret,
00725 const DBusGMethodInfo **method_ret)
00726 {
00727 const char *interface;
00728 const char *member;
00729 const char *signature;
00730 gboolean ret;
00731 const DBusGObjectInfo *info;
00732 int i;
00733
00734 interface = dbus_message_get_interface (message);
00735 member = dbus_message_get_member (message);
00736 signature = dbus_message_get_signature (message);
00737 ret = FALSE;
00738
00739 info = lookup_object_info (object);
00740 *object_ret = info;
00741
00742 for (i = 0; i < info->n_method_infos; i++)
00743 {
00744 const char *expected_member;
00745 const char *expected_interface;
00746 char *expected_signature;
00747 const DBusGMethodInfo *method;
00748
00749 method = &(info->method_infos[i]);
00750
00751
00752 expected_interface = method_interface_from_object_info (*object_ret, method);
00753 expected_member = method_name_from_object_info (*object_ret, method);
00754 expected_signature = method_input_signature_from_object_info (*object_ret, method);
00755
00756 if ((interface == NULL
00757 || strcmp (expected_interface, interface) == 0)
00758 && strcmp (expected_member, member) == 0
00759 && strcmp (expected_signature, signature) == 0)
00760 {
00761 g_free (expected_signature);
00762 *method_ret = method;
00763 return TRUE;
00764 }
00765 g_free (expected_signature);
00766 }
00767
00768 return ret;
00769 }
00770
00771 static char *
00772 gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
00773 const char *msg_interface,
00774 GQuark domain, gint code)
00775 {
00776 const char *domain_str;
00777 const char *code_str;
00778 GString *dbus_error_name;
00779
00780 domain_str = object_error_domain_prefix_from_object_info (object_info);
00781 code_str = object_error_code_from_object_info (object_info, domain, code);
00782
00783 if (!domain_str || !code_str)
00784 {
00785 DBusGErrorInfo *info;
00786
00787 g_static_rw_lock_reader_lock (&globals_lock);
00788
00789 if (error_metadata != NULL)
00790 info = g_datalist_id_get_data (&error_metadata, domain);
00791 else
00792 info = NULL;
00793
00794 g_static_rw_lock_reader_unlock (&globals_lock);
00795
00796 if (info)
00797 {
00798 GEnumValue *value;
00799 GEnumClass *klass;
00800
00801 klass = g_type_class_ref (info->code_enum);
00802 value = g_enum_get_value (klass, code);
00803 g_type_class_unref (klass);
00804
00805 domain_str = info->default_iface;
00806 code_str = value->value_nick;
00807 }
00808 }
00809
00810 if (!domain_str)
00811 domain_str = msg_interface;
00812
00813 if (!domain_str || !code_str)
00814 {
00815
00816 char *domain_from_quark;
00817
00818 dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
00819
00820 domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
00821 g_string_append (dbus_error_name, domain_from_quark);
00822 g_free (domain_from_quark);
00823
00824 g_string_append_printf (dbus_error_name, ".Code%d", code);
00825 }
00826 else
00827 {
00828 dbus_error_name = g_string_new (domain_str);
00829 g_string_append_c (dbus_error_name, '.');
00830 g_string_append (dbus_error_name, code_str);
00831 }
00832
00833 return g_string_free (dbus_error_name, FALSE);
00834 }
00835
00836 static DBusMessage *
00837 gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
00838 DBusMessage *message,
00839 GError *error)
00840 {
00841 DBusMessage *reply;
00842
00843 if (!error)
00844 {
00845 char *error_msg;
00846
00847 error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
00848 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
00849 g_free (error_msg);
00850 }
00851 else
00852 {
00853 if (error->domain == DBUS_GERROR)
00854 reply = dbus_message_new_error (message,
00855 dbus_g_error_get_name (error),
00856 error->message);
00857 else
00858 {
00859 char *error_name;
00860 error_name = gerror_domaincode_to_dbus_error_name (object_info,
00861 dbus_message_get_interface (message),
00862 error->domain, error->code);
00863 reply = dbus_message_new_error (message, error_name, error->message);
00864 g_free (error_name);
00865 }
00866 }
00867 return reply;
00868 }
00869
00874 struct _DBusGMethodInvocation {
00875 DBusGConnection *connection;
00876 DBusGMessage *message;
00877 const DBusGObjectInfo *object;
00878 const DBusGMethodInfo *method;
00879 };
00880
00881 static DBusHandlerResult
00882 invoke_object_method (GObject *object,
00883 const DBusGObjectInfo *object_info,
00884 const DBusGMethodInfo *method,
00885 DBusConnection *connection,
00886 DBusMessage *message)
00887 {
00888 gboolean had_error, call_only;
00889 GError *gerror;
00890 GValueArray *value_array;
00891 GValue return_value = {0,};
00892 GClosure closure;
00893 char *in_signature;
00894 GArray *out_param_values = NULL;
00895 GValueArray *out_param_gvalues = NULL;
00896 int out_param_count;
00897 int out_param_pos, out_param_gvalue_pos;
00898 DBusHandlerResult result;
00899 DBusMessage *reply;
00900 gboolean have_retval;
00901 gboolean retval_signals_error;
00902 gboolean retval_is_synthetic;
00903 gboolean retval_is_constant;
00904 const char *arg_metadata;
00905
00906 gerror = NULL;
00907
00908
00909
00910
00911 if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
00912 call_only = TRUE;
00913 else
00914 call_only = FALSE;
00915
00916 have_retval = FALSE;
00917 retval_signals_error = FALSE;
00918 retval_is_synthetic = FALSE;
00919 retval_is_constant = FALSE;
00920
00921
00922
00923
00924
00925
00926 memset (&closure, 0, sizeof (closure));
00927
00928 in_signature = method_input_signature_from_object_info (object_info, method);
00929
00930
00931 {
00932 GArray *types_array;
00933 guint n_params;
00934 const GType *types;
00935 DBusGValueMarshalCtx context;
00936 GError *error = NULL;
00937
00938 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00939 context.proxy = NULL;
00940
00941 types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
00942 n_params = types_array->len;
00943 types = (const GType*) types_array->data;
00944
00945 value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
00946 if (value_array == NULL)
00947 {
00948 g_free (in_signature);
00949 g_array_free (types_array, TRUE);
00950 reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
00951 dbus_connection_send (connection, reply, NULL);
00952 dbus_message_unref (reply);
00953 g_error_free (error);
00954 return DBUS_HANDLER_RESULT_HANDLED;
00955 }
00956 g_array_free (types_array, TRUE);
00957 }
00958
00959
00960 g_value_array_prepend (value_array, NULL);
00961 g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
00962 g_value_set_object (g_value_array_get_nth (value_array, 0), object);
00963
00964 if (call_only)
00965 {
00966 GValue context_value = {0,};
00967 DBusGMethodInvocation *context;
00968 context = g_new (DBusGMethodInvocation, 1);
00969 context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
00970 context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
00971 context->object = object_info;
00972 context->method = method;
00973 g_value_init (&context_value, G_TYPE_POINTER);
00974 g_value_set_pointer (&context_value, context);
00975 g_value_array_append (value_array, &context_value);
00976 }
00977 else
00978 {
00979 RetvalType retval;
00980 gboolean arg_in;
00981 gboolean arg_const;
00982 const char *argsig;
00983
00984 arg_metadata = method_arg_info_from_object_info (object_info, method);
00985
00986
00987 out_param_count = 0;
00988 while (*arg_metadata)
00989 {
00990 arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
00991 if (arg_in)
00992 continue;
00993 if (retval != RETVAL_NONE)
00994 {
00995 DBusSignatureIter tmp_sigiter;
00996
00997 g_assert (!have_retval);
00998 have_retval = TRUE;
00999 retval_is_synthetic = FALSE;
01000
01001 switch (retval)
01002 {
01003 case RETVAL_NONE:
01004 g_assert_not_reached ();
01005 break;
01006 case RETVAL_NOERROR:
01007 retval_signals_error = FALSE;
01008 break;
01009 case RETVAL_ERROR:
01010 retval_signals_error = TRUE;
01011 break;
01012 }
01013
01014 retval_is_constant = arg_const;
01015
01016
01017 dbus_signature_iter_init (&tmp_sigiter, argsig);
01018 g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
01019 }
01020 else
01021 {
01022
01023 out_param_count++;
01024 }
01025 }
01026
01027
01028
01029
01030
01031
01032
01033 if (!have_retval)
01034 {
01035 have_retval = TRUE;
01036 retval_is_synthetic = TRUE;
01037 retval_signals_error = TRUE;
01038 g_value_init (&return_value, G_TYPE_BOOLEAN);
01039 }
01040
01041
01042
01043
01044
01045
01046 out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
01047
01048
01049
01050
01051 out_param_gvalues = g_value_array_new (out_param_count);
01052 out_param_pos = 0;
01053 out_param_gvalue_pos = 0;
01054
01055
01056 arg_metadata = method_arg_info_from_object_info (object_info, method);
01057
01058
01059
01060
01061 while (*arg_metadata)
01062 {
01063 GValue value = {0, };
01064 GTypeCValue storage;
01065 DBusSignatureIter tmp_sigiter;
01066 GType current_gtype;
01067
01068 arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
01069
01070 if (arg_in || retval != RETVAL_NONE)
01071 continue;
01072
01073 dbus_signature_iter_init (&tmp_sigiter, argsig);
01074 current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
01075
01076 g_value_init (&value, G_TYPE_POINTER);
01077
01078
01079 if (current_gtype != G_TYPE_VALUE)
01080 {
01081 memset (&storage, 0, sizeof (storage));
01082 g_array_append_val (out_param_values, storage);
01083 g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
01084 out_param_pos++;
01085 }
01086 else
01087 {
01088 g_value_array_append (out_param_gvalues, NULL);
01089 g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
01090 out_param_gvalue_pos++;
01091 }
01092 g_value_array_append (value_array, &value);
01093 }
01094 }
01095
01096
01097 if (retval_signals_error)
01098 {
01099 g_assert (have_retval);
01100 g_value_array_append (value_array, NULL);
01101 g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
01102 g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
01103 }
01104
01105
01106 method->marshaller (&closure, have_retval ? &return_value : NULL,
01107 value_array->n_values,
01108 value_array->values,
01109 NULL, method->function);
01110 if (call_only)
01111 {
01112 result = DBUS_HANDLER_RESULT_HANDLED;
01113 goto done;
01114 }
01115 if (retval_signals_error)
01116 had_error = _dbus_gvalue_signals_error (&return_value);
01117 else
01118 had_error = FALSE;
01119
01120 if (!had_error)
01121 {
01122 DBusMessageIter iter;
01123
01124 reply = dbus_message_new_method_return (message);
01125 if (reply == NULL)
01126 goto nomem;
01127
01128
01129 dbus_message_iter_init_append (reply, &iter);
01130
01131
01132 if (have_retval && !retval_is_synthetic)
01133 {
01134 if (!_dbus_gvalue_marshal (&iter, &return_value))
01135 goto nomem;
01136 if (!retval_is_constant)
01137 g_value_unset (&return_value);
01138 }
01139
01140
01141 arg_metadata = method_arg_info_from_object_info (object_info, method);
01142
01143
01144 out_param_pos = 0;
01145 out_param_gvalue_pos = 0;
01146 while (*arg_metadata)
01147 {
01148 GValue gvalue = {0, };
01149 const char *arg_name;
01150 gboolean arg_in;
01151 gboolean constval;
01152 RetvalType retval;
01153 const char *arg_signature;
01154 DBusSignatureIter argsigiter;
01155
01156 do
01157 {
01158
01159
01160 arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
01161 }
01162 while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
01163
01164
01165
01166
01167 if (arg_in || retval != RETVAL_NONE)
01168 break;
01169
01170 dbus_signature_iter_init (&argsigiter, arg_signature);
01171
01172 g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
01173 if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
01174 {
01175 if (!_dbus_gvalue_take (&gvalue,
01176 &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
01177 g_assert_not_reached ();
01178 out_param_pos++;
01179 }
01180 else
01181 {
01182 g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
01183 out_param_gvalue_pos++;
01184 }
01185
01186 if (!_dbus_gvalue_marshal (&iter, &gvalue))
01187 goto nomem;
01188
01189
01190
01191
01192 if (!constval)
01193 g_value_unset (&gvalue);
01194 }
01195 }
01196 else
01197 reply = gerror_to_dbus_error_message (object_info, message, gerror);
01198
01199 if (reply)
01200 {
01201 dbus_connection_send (connection, reply, NULL);
01202 dbus_message_unref (reply);
01203 }
01204
01205 result = DBUS_HANDLER_RESULT_HANDLED;
01206 done:
01207 g_free (in_signature);
01208 if (!call_only)
01209 {
01210 g_array_free (out_param_values, TRUE);
01211 g_value_array_free (out_param_gvalues);
01212 }
01213 g_value_array_free (value_array);
01214 return result;
01215 nomem:
01216 result = DBUS_HANDLER_RESULT_NEED_MEMORY;
01217 goto done;
01218 }
01219
01220 static DBusHandlerResult
01221 gobject_message_function (DBusConnection *connection,
01222 DBusMessage *message,
01223 void *user_data)
01224 {
01225 GParamSpec *pspec;
01226 GObject *object;
01227 gboolean setter;
01228 gboolean getter;
01229 char *s;
01230 const char *wincaps_propname;
01231
01232 DBusMessageIter iter;
01233 const DBusGMethodInfo *method;
01234 const DBusGObjectInfo *object_info;
01235
01236 object = G_OBJECT (user_data);
01237
01238 if (dbus_message_is_method_call (message,
01239 DBUS_INTERFACE_INTROSPECTABLE,
01240 "Introspect"))
01241 return handle_introspect (connection, message, object);
01242
01243
01244 if (lookup_object_and_method (object, message, &object_info, &method))
01245 return invoke_object_method (object, object_info, method, connection, message);
01246
01247
01248
01249
01250 getter = FALSE;
01251 setter = FALSE;
01252 if (dbus_message_is_method_call (message,
01253 DBUS_INTERFACE_PROPERTIES,
01254 "Get"))
01255 getter = TRUE;
01256 else if (dbus_message_is_method_call (message,
01257 DBUS_INTERFACE_PROPERTIES,
01258 "Set"))
01259 setter = TRUE;
01260
01261 if (!(setter || getter))
01262 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01263
01264 dbus_message_iter_init (message, &iter);
01265
01266 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01267 {
01268 g_warning ("Property get or set does not have an interface string as first arg\n");
01269 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01270 }
01271
01272
01273
01274
01275 dbus_message_iter_next (&iter);
01276
01277 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
01278 {
01279 g_warning ("Property get or set does not have a property name string as second arg\n");
01280 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01281 }
01282 dbus_message_iter_get_basic (&iter, &wincaps_propname);
01283 dbus_message_iter_next (&iter);
01284
01285 s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
01286
01287 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
01288 s);
01289
01290 g_free (s);
01291
01292 if (pspec != NULL)
01293 {
01294 DBusMessage *ret;
01295
01296 if (setter)
01297 {
01298 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
01299 {
01300 g_warning ("Property set does not have a variant value as third arg\n");
01301 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01302 }
01303
01304 ret = set_object_property (connection, message, &iter,
01305 object, pspec);
01306 dbus_message_iter_next (&iter);
01307 }
01308 else if (getter)
01309 {
01310 ret = get_object_property (connection, message,
01311 object, pspec);
01312 }
01313 else
01314 {
01315 g_assert_not_reached ();
01316 ret = NULL;
01317 }
01318
01319 g_assert (ret != NULL);
01320
01321 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
01322 g_warning ("Property get or set had too many arguments\n");
01323
01324 dbus_connection_send (connection, ret, NULL);
01325 dbus_message_unref (ret);
01326 return DBUS_HANDLER_RESULT_HANDLED;
01327 }
01328
01329 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01330 }
01331
01332 static DBusObjectPathVTable gobject_dbus_vtable = {
01333 gobject_unregister_function,
01334 gobject_message_function,
01335 NULL
01336 };
01337
01338 typedef struct {
01339 GClosure closure;
01340 DBusGConnection *connection;
01341 GObject *object;
01342 const char *signame;
01343 const char *sigiface;
01344 } DBusGSignalClosure;
01345
01346 static GClosure *
01347 dbus_g_signal_closure_new (DBusGConnection *connection,
01348 GObject *object,
01349 const char *signame,
01350 const char *sigiface)
01351 {
01352 DBusGSignalClosure *closure;
01353
01354 closure = (DBusGSignalClosure*) g_closure_new_simple (sizeof (DBusGSignalClosure), NULL);
01355
01356 closure->connection = dbus_g_connection_ref (connection);
01357 closure->object = object;
01358 closure->signame = signame;
01359 closure->sigiface = sigiface;
01360 return (GClosure*) closure;
01361 }
01362
01363 static void
01364 dbus_g_signal_closure_finalize (gpointer data,
01365 GClosure *closure)
01366 {
01367 DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
01368
01369 dbus_g_connection_unref (sigclosure->connection);
01370 }
01371
01372 static void
01373 signal_emitter_marshaller (GClosure *closure,
01374 GValue *retval,
01375 guint n_param_values,
01376 const GValue *param_values,
01377 gpointer invocation_hint,
01378 gpointer marshal_data)
01379 {
01380 DBusGSignalClosure *sigclosure;
01381 DBusMessage *signal;
01382 DBusMessageIter iter;
01383 guint i;
01384 const char *path;
01385
01386 sigclosure = (DBusGSignalClosure *) closure;
01387
01388 g_assert (retval == NULL);
01389
01390 path = _dbus_gobject_get_path (sigclosure->object);
01391
01392 g_assert (path != NULL);
01393
01394 signal = dbus_message_new_signal (path,
01395 sigclosure->sigiface,
01396 sigclosure->signame);
01397 if (!signal)
01398 {
01399 g_error ("out of memory");
01400 return;
01401 }
01402
01403 dbus_message_iter_init_append (signal, &iter);
01404
01405
01406 for (i = 1; i < n_param_values; i++)
01407 {
01408 if (!_dbus_gvalue_marshal (&iter,
01409 (GValue *) (&(param_values[i]))))
01410 {
01411 g_warning ("failed to marshal parameter %d for signal %s",
01412 i, sigclosure->signame);
01413 goto out;
01414 }
01415 }
01416 dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
01417 signal, NULL);
01418 out:
01419 dbus_message_unref (signal);
01420 }
01421
01422 static void
01423 export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
01424 {
01425 GType gtype;
01426 const char *sigdata;
01427 const char *iface;
01428 const char *signame;
01429
01430 gtype = G_TYPE_FROM_INSTANCE (object);
01431
01432 sigdata = info->exported_signals;
01433
01434 while (*sigdata != '\0')
01435 {
01436 guint id;
01437 GSignalQuery query;
01438 GClosure *closure;
01439 char *s;
01440
01441 sigdata = propsig_iterate (sigdata, &iface, &signame);
01442
01443 s = _dbus_gutils_wincaps_to_uscore (signame);
01444
01445 id = g_signal_lookup (s, gtype);
01446 if (id == 0)
01447 {
01448 g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
01449 s, signame, g_type_name (gtype));
01450 g_free (s);
01451 continue;
01452 }
01453
01454 g_signal_query (id, &query);
01455
01456 if (query.return_type != G_TYPE_NONE)
01457 {
01458 g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
01459 s, g_type_name (gtype), g_type_name (query.return_type));
01460 g_free (s);
01461 continue;
01462 }
01463
01464 closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
01465 g_closure_set_marshal (closure, signal_emitter_marshaller);
01466
01467 g_signal_connect_closure_by_id (object,
01468 id,
01469 0,
01470 closure,
01471 FALSE);
01472
01473 g_closure_add_finalize_notifier (closure, NULL,
01474 dbus_g_signal_closure_finalize);
01475 g_free (s);
01476 }
01477 }
01478
01479 #include "dbus-glib-error-switch.h"
01480
01481 void
01482 dbus_set_g_error (GError **gerror,
01483 DBusError *error)
01484 {
01485 int code;
01486
01487 code = dbus_error_to_gerror_code (error->name);
01488 if (code != DBUS_GERROR_REMOTE_EXCEPTION)
01489 g_set_error (gerror, DBUS_GERROR,
01490 code,
01491 "%s",
01492 error->message);
01493 else
01494 g_set_error (gerror, DBUS_GERROR,
01495 code,
01496 "%s%c%s",
01497 error->message ? error->message : "",
01498 '\0',
01499 error->name);
01500 }
01501
01502 static void
01503 dbus_g_error_info_free (gpointer p)
01504 {
01505 DBusGErrorInfo *info;
01506
01507 info = p;
01508
01509 g_free (info->default_iface);
01510 g_free (info);
01511 }
01512
01514
01534 void
01535 dbus_g_object_type_install_info (GType object_type,
01536 const DBusGObjectInfo *info)
01537 {
01538 g_return_if_fail (G_TYPE_IS_CLASSED (object_type));
01539
01540 _dbus_g_value_types_init ();
01541
01542 g_type_set_qdata (object_type,
01543 dbus_g_object_type_dbus_metadata_quark (),
01544 (gpointer) info);
01545 }
01546
01556 void
01557 dbus_g_error_domain_register (GQuark domain,
01558 const char *default_iface,
01559 GType code_enum)
01560 {
01561 DBusGErrorInfo *info;
01562
01563 g_return_if_fail (g_quark_to_string (domain) != NULL);
01564 g_return_if_fail (code_enum != G_TYPE_INVALID);
01565 g_return_if_fail (G_TYPE_FUNDAMENTAL (code_enum) == G_TYPE_ENUM);
01566
01567 g_static_rw_lock_writer_lock (&globals_lock);
01568
01569 if (error_metadata == NULL)
01570 g_datalist_init (&error_metadata);
01571
01572 info = g_datalist_id_get_data (&error_metadata, domain);
01573
01574 if (info != NULL)
01575 {
01576 g_warning ("Metadata for error domain \"%s\" already registered\n",
01577 g_quark_to_string (domain));
01578 }
01579 else
01580 {
01581 info = g_new0 (DBusGErrorInfo, 1);
01582 info->default_iface = g_strdup (default_iface);
01583 info->code_enum = code_enum;
01584
01585 g_datalist_id_set_data_full (&error_metadata,
01586 domain,
01587 info,
01588 dbus_g_error_info_free);
01589 }
01590
01591 g_static_rw_lock_writer_unlock (&globals_lock);
01592 }
01593
01594 static void
01595 unregister_gobject (DBusGConnection *connection, GObject *dead)
01596 {
01597 char *path;
01598 path = g_object_steal_data (dead, "dbus_glib_object_path");
01599 dbus_connection_unregister_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection), path);
01600 g_free (path);
01601 }
01602
01616 void
01617 dbus_g_connection_register_g_object (DBusGConnection *connection,
01618 const char *at_path,
01619 GObject *object)
01620 {
01621 const DBusGObjectInfo *info;
01622 g_return_if_fail (connection != NULL);
01623 g_return_if_fail (at_path != NULL);
01624 g_return_if_fail (G_IS_OBJECT (object));
01625
01626 info = lookup_object_info (object);
01627 if (info == NULL)
01628 {
01629 g_warning ("No introspection data registered for object class \"%s\"",
01630 g_type_name (G_TYPE_FROM_INSTANCE (object)));
01631 return;
01632 }
01633
01634 if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
01635 at_path,
01636 &gobject_dbus_vtable,
01637 object))
01638 {
01639 g_error ("Failed to register GObject with DBusConnection");
01640 return;
01641 }
01642
01643 export_signals (connection, info, object);
01644
01645 g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
01646 g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
01647 }
01648
01649 GObject *
01650 dbus_g_connection_lookup_g_object (DBusGConnection *connection,
01651 const char *at_path)
01652 {
01653 gpointer ret;
01654 if (!dbus_connection_get_object_path_data (DBUS_CONNECTION_FROM_G_CONNECTION (connection), at_path, &ret))
01655 return NULL;
01656 return ret;
01657 }
01658
01659 typedef struct {
01660 GType rettype;
01661 guint n_params;
01662 GType *params;
01663 } DBusGFuncSignature;
01664
01665 static guint
01666 funcsig_hash (gconstpointer key)
01667 {
01668 const DBusGFuncSignature *sig = key;
01669 GType *types;
01670 guint ret;
01671 guint i;
01672
01673 ret = sig->rettype;
01674 types = sig->params;
01675
01676 for (i = 0; i < sig->n_params; i++)
01677 {
01678 ret += (int) (*types);
01679 types++;
01680 }
01681
01682 return ret;
01683 }
01684
01685 static gboolean
01686 funcsig_equal (gconstpointer aval,
01687 gconstpointer bval)
01688 {
01689 const DBusGFuncSignature *a = aval;
01690 const DBusGFuncSignature *b = bval;
01691 const GType *atypes;
01692 const GType *btypes;
01693 guint i;
01694
01695 if (a->rettype != b->rettype
01696 || a->n_params != b->n_params)
01697 return FALSE;
01698
01699 atypes = a->params;
01700 btypes = b->params;
01701
01702 for (i = 0; i < a->n_params; i++)
01703 {
01704 if (*btypes != *atypes)
01705 return FALSE;
01706 atypes++;
01707 btypes++;
01708 }
01709
01710 return TRUE;
01711 }
01712
01713 GClosureMarshal
01714 _dbus_gobject_lookup_marshaller (GType rettype,
01715 guint n_params,
01716 const GType *param_types)
01717 {
01718 GClosureMarshal ret;
01719 DBusGFuncSignature sig;
01720 GType *params;
01721 guint i;
01722
01723
01724 rettype = G_TYPE_FUNDAMENTAL (rettype);
01725 params = g_new (GType, n_params);
01726 for (i = 0; i < n_params; i++)
01727 params[i] = G_TYPE_FUNDAMENTAL (param_types[i]);
01728
01729 sig.rettype = rettype;
01730 sig.n_params = n_params;
01731 sig.params = params;
01732
01733 g_static_rw_lock_reader_lock (&globals_lock);
01734
01735 if (marshal_table)
01736 ret = g_hash_table_lookup (marshal_table, &sig);
01737 else
01738 ret = NULL;
01739
01740 g_static_rw_lock_reader_unlock (&globals_lock);
01741
01742 if (ret == NULL)
01743 {
01744 if (rettype == G_TYPE_NONE)
01745 {
01746 if (n_params == 0)
01747 ret = g_cclosure_marshal_VOID__VOID;
01748 else if (n_params == 1)
01749 {
01750 switch (params[0])
01751 {
01752 case G_TYPE_BOOLEAN:
01753 ret = g_cclosure_marshal_VOID__BOOLEAN;
01754 break;
01755 case G_TYPE_UCHAR:
01756 ret = g_cclosure_marshal_VOID__UCHAR;
01757 break;
01758 case G_TYPE_INT:
01759 ret = g_cclosure_marshal_VOID__INT;
01760 break;
01761 case G_TYPE_UINT:
01762 ret = g_cclosure_marshal_VOID__UINT;
01763 break;
01764 case G_TYPE_DOUBLE:
01765 ret = g_cclosure_marshal_VOID__DOUBLE;
01766 break;
01767 case G_TYPE_STRING:
01768 ret = g_cclosure_marshal_VOID__STRING;
01769 break;
01770 case G_TYPE_BOXED:
01771 ret = g_cclosure_marshal_VOID__BOXED;
01772 break;
01773 }
01774 }
01775 else if (n_params == 3
01776 && params[0] == G_TYPE_STRING
01777 && params[1] == G_TYPE_STRING
01778 && params[2] == G_TYPE_STRING)
01779 {
01780 ret = _dbus_g_marshal_NONE__STRING_STRING_STRING;
01781 }
01782 }
01783 }
01784
01785 g_free (params);
01786 return ret;
01787 }
01788
01800 void
01801 dbus_g_object_register_marshaller (GClosureMarshal marshaller,
01802 GType rettype,
01803 ...)
01804 {
01805 va_list args;
01806 GArray *types;
01807 GType gtype;
01808
01809 va_start (args, rettype);
01810
01811 types = g_array_new (TRUE, TRUE, sizeof (GType));
01812
01813 while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
01814 g_array_append_val (types, gtype);
01815
01816 dbus_g_object_register_marshaller_array (marshaller, rettype,
01817 types->len, (GType*) types->data);
01818
01819 g_array_free (types, TRUE);
01820 va_end (args);
01821 }
01822
01832 void
01833 dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
01834 GType rettype,
01835 guint n_types,
01836 const GType* types)
01837 {
01838 DBusGFuncSignature *sig;
01839 guint i;
01840
01841 g_static_rw_lock_writer_lock (&globals_lock);
01842
01843 if (marshal_table == NULL)
01844 marshal_table = g_hash_table_new_full (funcsig_hash,
01845 funcsig_equal,
01846 g_free,
01847 NULL);
01848 sig = g_new0 (DBusGFuncSignature, 1);
01849 sig->rettype = G_TYPE_FUNDAMENTAL (rettype);
01850 sig->n_params = n_types;
01851 sig->params = g_new (GType, n_types);
01852 for (i = 0; i < n_types; i++)
01853 sig->params[i] = G_TYPE_FUNDAMENTAL (types[i]);
01854
01855 g_hash_table_insert (marshal_table, sig, marshaller);
01856
01857 g_static_rw_lock_writer_unlock (&globals_lock);
01858 }
01859
01866 void
01867 dbus_g_method_return (DBusGMethodInvocation *context, ...)
01868 {
01869 DBusMessage *reply;
01870 DBusMessageIter iter;
01871 va_list args;
01872 char *out_sig;
01873 GArray *argsig;
01874 guint i;
01875
01876 reply = dbus_message_new_method_return (dbus_g_message_get_message (context->message));
01877 out_sig = method_output_signature_from_object_info (context->object, context->method);
01878 argsig = _dbus_gtypes_from_arg_signature (out_sig, FALSE);
01879
01880 dbus_message_iter_init_append (reply, &iter);
01881
01882 va_start (args, context);
01883 for (i = 0; i < argsig->len; i++)
01884 {
01885 GValue value = {0,};
01886 char *error;
01887 g_value_init (&value, g_array_index (argsig, GType, i));
01888 error = NULL;
01889 G_VALUE_COLLECT (&value, args, G_VALUE_NOCOPY_CONTENTS, &error);
01890 if (error)
01891 {
01892 g_warning(error);
01893 g_free (error);
01894 }
01895 _dbus_gvalue_marshal (&iter, &value);
01896 }
01897 va_end (args);
01898
01899 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01900 dbus_message_unref (reply);
01901
01902 dbus_g_connection_unref (context->connection);
01903 dbus_g_message_unref (context->message);
01904 g_free (context);
01905 g_free (out_sig);
01906 }
01907
01915 void
01916 dbus_g_method_return_error (DBusGMethodInvocation *context, GError *error)
01917 {
01918 DBusMessage *reply;
01919 reply = gerror_to_dbus_error_message (context->object, dbus_g_message_get_message (context->message), error);
01920 dbus_connection_send (dbus_g_connection_get_connection (context->connection), reply, NULL);
01921 dbus_message_unref (reply);
01922 g_free (context);
01923 }
01924
01926
01927 const char * _dbus_gobject_get_path (GObject *obj)
01928 {
01929 return g_object_get_data (obj, "dbus_glib_object_path");
01930 }
01931
01932 #ifdef DBUS_BUILD_TESTS
01933 #include <stdlib.h>
01934
01935 static void
01936 _dummy_function (void)
01937 {
01938 }
01939
01940
01941
01942
01943 static const DBusGMethodInfo dbus_glib_internal_test_methods[] = {
01944 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 0 },
01945 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 49 },
01946 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 117 },
01947 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 191 },
01948 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 270 },
01949 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 320 },
01950 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 391 },
01951 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 495 },
01952 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 623 },
01953 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 693 },
01954 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 765 },
01955 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 838 },
01956 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 911 },
01957 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 988 },
01958 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1064 },
01959 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1140 },
01960 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1204 },
01961 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1278 },
01962 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1347 },
01963 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1408 },
01964 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1460 },
01965 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1533 },
01966 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1588 },
01967 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1647 },
01968 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1730 },
01969 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1784 },
01970 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1833 },
01971 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1895 },
01972 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1947 },
01973 { (GCallback) _dummy_function, g_cclosure_marshal_VOID__VOID, 1999 },
01974 };
01975
01976 const DBusGObjectInfo dbus_glib_internal_test_object_info = {
01977 0,
01978 dbus_glib_internal_test_methods,
01979 30,
01980 "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",
01981 "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",
01982 "\0"
01983 };
01984
01985
01991 gboolean
01992 _dbus_gobject_test (const char *test_data_dir)
01993 {
01994 int i;
01995 const char *arg;
01996 const char *arg_name;
01997 gboolean arg_in;
01998 gboolean constval;
01999 RetvalType retval;
02000 const char *arg_signature;
02001 const char *sigdata;
02002 const char *iface;
02003 const char *signame;
02004
02005 static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
02006 { "SetFoo", "set_foo" },
02007 { "Foo", "foo" },
02008 { "GetFooBar", "get_foo_bar" },
02009 { "Hello", "hello" }
02010
02011
02012
02013 };
02014
02015
02016
02017
02018
02019
02020 arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02021 &(dbus_glib_internal_test_methods[0]));
02022 g_assert (*arg == '\0');
02023
02024
02025 arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02026 &(dbus_glib_internal_test_methods[1]));
02027 g_assert (*arg != '\0');
02028 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02029 g_assert (!strcmp (arg_name, "x"));
02030 g_assert (arg_in == TRUE);
02031 g_assert (!strcmp (arg_signature, "u"));
02032 g_assert (*arg != '\0');
02033 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02034 g_assert (arg_in == FALSE);
02035 g_assert (retval == RETVAL_NONE);
02036 g_assert (!strcmp (arg_signature, "u"));
02037 g_assert (*arg == '\0');
02038
02039
02040 arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02041 &(dbus_glib_internal_test_methods[2]));
02042 g_assert (*arg != '\0');
02043 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02044 g_assert (!strcmp (arg_name, "x"));
02045 g_assert (arg_in == TRUE);
02046 g_assert (!strcmp (arg_signature, "u"));
02047 g_assert (*arg != '\0');
02048 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02049 g_assert (retval == RETVAL_NOERROR);
02050 g_assert (arg_in == FALSE);
02051 g_assert (!strcmp (arg_signature, "u"));
02052 g_assert (*arg == '\0');
02053
02054
02055 arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02056 &(dbus_glib_internal_test_methods[3]));
02057 g_assert (*arg != '\0');
02058 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02059 g_assert (!strcmp (arg_name, "x"));
02060 g_assert (arg_in == TRUE);
02061 g_assert (!strcmp (arg_signature, "u"));
02062 g_assert (*arg != '\0');
02063 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02064 g_assert (retval == RETVAL_ERROR);
02065 g_assert (arg_in == FALSE);
02066 g_assert (!strcmp (arg_signature, "u"));
02067 g_assert (*arg == '\0');
02068
02069
02070 arg = method_arg_info_from_object_info (&dbus_glib_internal_test_object_info,
02071 &(dbus_glib_internal_test_methods[8]));
02072 g_assert (*arg != '\0');
02073 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02074 g_assert (!strcmp (arg_name, "val"));
02075 g_assert (arg_in == TRUE);
02076 g_assert (!strcmp (arg_signature, "v"));
02077 g_assert (*arg != '\0');
02078 arg = arg_iterate (arg, &arg_name, &arg_in, &constval, &retval, &arg_signature);
02079 g_assert (retval == RETVAL_NONE);
02080 g_assert (arg_in == FALSE);
02081 g_assert (!strcmp (arg_signature, "s"));
02082 g_assert (*arg == '\0');
02083
02084 sigdata = dbus_glib_internal_test_object_info.exported_signals;
02085 g_assert (*sigdata != '\0');
02086 sigdata = propsig_iterate (sigdata, &iface, &signame);
02087 g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
02088 g_assert (!strcmp (signame, "Frobnicate"));
02089 g_assert (*sigdata != '\0');
02090 sigdata = propsig_iterate (sigdata, &iface, &signame);
02091 g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02092 g_assert (!strcmp (signame, "Sig0"));
02093 g_assert (*sigdata != '\0');
02094 sigdata = propsig_iterate (sigdata, &iface, &signame);
02095 g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02096 g_assert (!strcmp (signame, "Sig1"));
02097 g_assert (*sigdata != '\0');
02098 sigdata = propsig_iterate (sigdata, &iface, &signame);
02099 g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
02100 g_assert (!strcmp (signame, "Sig2"));
02101 g_assert (*sigdata == '\0');
02102
02103
02104 i = 0;
02105 while (i < (int) G_N_ELEMENTS (name_pairs))
02106 {
02107 char *uscore;
02108 char *wincaps;
02109
02110 uscore = _dbus_gutils_wincaps_to_uscore (name_pairs[i].wincaps);
02111 wincaps = uscore_to_wincaps (name_pairs[i].uscore);
02112
02113 if (strcmp (uscore, name_pairs[i].uscore) != 0)
02114 {
02115 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02116 name_pairs[i].wincaps, name_pairs[i].uscore,
02117 uscore);
02118 exit (1);
02119 }
02120
02121 if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
02122 {
02123 g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
02124 name_pairs[i].uscore, name_pairs[i].wincaps,
02125 wincaps);
02126 exit (1);
02127 }
02128
02129 g_free (uscore);
02130 g_free (wincaps);
02131
02132 ++i;
02133 }
02134
02135 return TRUE;
02136 }
02137
02138 #endif