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