diff options
author | Colin Walters <walters@verbum.org> | 2010-04-19 16:47:11 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2010-05-26 11:19:53 -0400 |
commit | 9a6bce9b615abca6068348c1606ba8eaf13d9ae0 (patch) | |
tree | 652c551306118ccc508f12eaf635762b10f3a81b | |
parent | 9ebe54e7ec35b5781ab48b3a9efbc4bef5867eeb (diff) |
Respect property access flags for writing, allow disabling for readsrhel5
Because DBus-GLib originally was designed as a generic "object mapping"
binding, the handler for org.freedesktop.DBus.Properties simply
allowed access (read or write) to any GObject property that was
exported.
Later, the (compile time) introspection XML was added, and while we only
listed "exported" properties in the dynamic introspection XML, we
still allowed Get or Set calls to any property that was valid.
With this patch, we deny writes to properties which aren't listed
in the XML, or are listed as read-only.
For backwards compatibility however, we still allow reads. A
service may disable this by calling
dbus_glib_global_set_disable_legacy_property_access().
-rw-r--r-- | dbus/dbus-binding-tool-glib.c | 48 | ||||
-rw-r--r-- | dbus/dbus-glib.h | 2 | ||||
-rw-r--r-- | dbus/dbus-gobject.c | 412 | ||||
-rw-r--r-- | test/core/Makefile.am | 4 | ||||
-rw-r--r-- | test/core/my-object.c | 853 | ||||
-rw-r--r-- | test/core/my-object.h | 118 | ||||
-rw-r--r-- | test/core/test-dbus-glib.c | 286 | ||||
-rw-r--r-- | test/core/test-service-glib.c | 832 | ||||
-rw-r--r-- | test/core/test-service-glib.xml | 7 |
9 files changed, 1664 insertions, 898 deletions
diff --git a/dbus/dbus-binding-tool-glib.c b/dbus/dbus-binding-tool-glib.c index adede27..7e280f6 100644 --- a/dbus/dbus-binding-tool-glib.c +++ b/dbus/dbus-binding-tool-glib.c @@ -38,6 +38,10 @@ #include <string.h> #include <unistd.h> +/* Remember to grep for ->format_version in the code if you change this, + * most changes should be in dbus-gobject.c. */ +#define FORMAT_VERSION 1 + #define MARSHAL_PREFIX "dbus_glib_marshal_" typedef struct @@ -489,10 +493,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) /* Information about the object. */ - if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n", - channel, error, data->prefix)) - goto io_lose; - WRITE_OR_LOSE (" 0,\n"); + if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = { %d,\n", + channel, error, data->prefix, FORMAT_VERSION)) + goto io_lose; if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, data->prefix)) goto io_lose; if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count)) @@ -736,13 +739,36 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp)) { PropertyInfo *prop; - - prop = tmp->data; - - g_string_append (data->property_blob, interface_info_get_name (interface)); - g_string_append_c (data->property_blob, '\0'); - g_string_append (data->property_blob, property_info_get_name (prop)); - g_string_append_c (data->property_blob, '\0'); + PropertyAccessFlags access_flags; + const char *access_string; + char *uscored; + + prop = tmp->data; + + access_flags = property_info_get_access (prop); + if ((access_flags & PROPERTY_READ) && (access_flags & PROPERTY_WRITE)) + access_string = "readwrite"; + else if (access_flags & PROPERTY_READ) + access_string = "read"; + else if (access_flags & PROPERTY_WRITE) + access_string = "write"; + else + continue; + + /* We append both in the blob so we have to malloc() less when processing + * properties */ + uscored = _dbus_gutils_wincaps_to_uscore (property_info_get_name (prop)); + + g_string_append (data->property_blob, interface_info_get_name (interface)); + g_string_append_c (data->property_blob, '\0'); + g_string_append (data->property_blob, property_info_get_name (prop)); + g_string_append_c (data->property_blob, '\0'); + g_string_append (data->property_blob, uscored); + g_string_append_c (data->property_blob, '\0'); + g_string_append (data->property_blob, access_string); + g_string_append_c (data->property_blob, '\0'); + + g_free (uscored); } } return TRUE; diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index 664e89f..a3a3597 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -150,6 +150,8 @@ struct _DBusGObjectInfo const char *exported_properties; }; +void dbus_glib_global_set_disable_legacy_property_access (void); + void dbus_g_object_type_install_info (GType object_type, const DBusGObjectInfo *info); diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c index ec93ad4..1755f2c 100644 --- a/dbus/dbus-gobject.c +++ b/dbus/dbus-gobject.c @@ -42,9 +42,28 @@ typedef struct } DBusGErrorInfo; static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT; +/* See comments in check_property_access */ +static gboolean disable_legacy_property_access = FALSE; static GHashTable *marshal_table = NULL; static GData *error_metadata = NULL; +/* Ugly yes - but we have to accept strings from both formats */ +static gboolean +compare_strings_ignoring_uscore_vs_dash (const char *a, const char *b) +{ + guint i; + + for (i = 0; a[i] && b[i]; i++) + { + if ((a[i] == '-' && b[i] == '_') + || (a[i] == '_' && b[i] == '-')) + continue; + if (a[i] != b[i]) + return FALSE; + } + return (a[i] == '\0') && (b[i] == '\0'); +} + static char* uscore_to_wincaps (const char *uscore) { @@ -270,7 +289,7 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object, } static const char * -propsig_iterate (const char *data, const char **iface, const char **name) +signal_iterate (const char *data, const char **iface, const char **name) { *iface = data; @@ -280,6 +299,108 @@ propsig_iterate (const char *data, const char **iface, const char **name) return string_table_next (data); } +static const char * +property_iterate (const char *data, + int format_version, + const char **iface, + const char **exported_name, + const char **name_uscored, + const char **access_type) +{ + *iface = data; + + data = string_table_next (data); + *exported_name = data; + + data = string_table_next (data); + if (format_version == 1) + { + *name_uscored = data; + data = string_table_next (data); + *access_type = data; + return string_table_next (data); + } + else + { + /* This tells the caller they need to compute it */ + *name_uscored = NULL; + /* We don't know here, however note that we will still check against the + * readable/writable flags from GObject's metadata. + */ + *access_type = "readwrite"; + return data; + } +} + +/** + * property_info_from_object_info: + * @object: introspection data + * @interface_name: (allow-none): Expected interface name, or %NULL for any + * @property_name: Expected property name (can use "-" or "_" as separator) + * @access_type: (out): Can be one of "read", "write", "readwrite" + * + * Look up property introspection data for the given interface/name pair. + * + * Returns: %TRUE if property was found + */ +static gboolean +property_info_from_object_info (const DBusGObjectInfo *object, + const char *interface_name, + const char *property_name, + const char **access_type) +{ + const char *properties_iter; + + properties_iter = object->exported_properties; + while (properties_iter != NULL && *properties_iter) + { + const char *cur_interface_name; + const char *cur_property_name; + const char *cur_uscore_property_name; + const char *cur_access_type; + + + properties_iter = property_iterate (properties_iter, object->format_version, + &cur_interface_name, &cur_property_name, + &cur_uscore_property_name, &cur_access_type); + + if (interface_name && strcmp (interface_name, cur_interface_name) != 0) + continue; + + /* This big pile of ugly is necessary to support the matrix resulting from multiplying + * (v0 data, v1 data) * (FooBar, foo-bar) + * In v1 data we have both forms of string, so we do a comparison against both without + * having to malloc. + * For v0 data, we need to reconstruct the foo-bar form. + * + * Adding to the complexity is that we *also* have to ignore the distinction between + * '-' and '_', because g_object_{get,set} does. + */ + /* First, compare against the primary property name - no malloc required */ + if (!compare_strings_ignoring_uscore_vs_dash (property_name, cur_property_name)) + { + if (cur_uscore_property_name != NULL + && !compare_strings_ignoring_uscore_vs_dash (property_name, cur_uscore_property_name)) + continue; + else + { + /* v0 metadata, construct uscore */ + char *tmp_uscored; + gboolean matches; + tmp_uscored = _dbus_gutils_wincaps_to_uscore (cur_property_name); + matches = compare_strings_ignoring_uscore_vs_dash (property_name, tmp_uscored); + g_free (tmp_uscored); + if (!matches) + continue; + } + } + + *access_type = cur_access_type; + return TRUE; + } + return FALSE; +} + static GQuark dbus_g_object_type_dbus_metadata_quark (void) { @@ -290,11 +411,17 @@ dbus_g_object_type_dbus_metadata_quark (void) return quark; } -static GList * -lookup_object_info (GObject *object) +/* Iterator function should return FALSE to stop iteration, TRUE to continue */ +typedef gboolean (*ForeachObjectInfoFn) (const DBusGObjectInfo *info, + GType gtype, + gpointer user_data); + +static void +foreach_object_info (GObject *object, + ForeachObjectInfoFn callback, + gpointer user_data) { GType *interfaces, *p; - GList *info_list = NULL; const DBusGObjectInfo *info; GType classtype; @@ -304,7 +431,10 @@ lookup_object_info (GObject *object) { info = g_type_get_qdata (*p, dbus_g_object_type_dbus_metadata_quark ()); if (info != NULL && info->format_version >= 0) - info_list = g_list_prepend (info_list, (gpointer) info); + { + if (!callback (info, *p, user_data)) + break; + } } g_free (interfaces); @@ -313,16 +443,85 @@ lookup_object_info (GObject *object) { info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ()); if (info != NULL && info->format_version >= 0) - info_list = g_list_prepend (info_list, (gpointer) info); + { + if (!callback (info, classtype, user_data)) + break; + } } - /* if needed only: - return g_list_reverse (info_list); - */ - +} + +static gboolean +lookup_object_info_cb (const DBusGObjectInfo *info, + GType gtype, + gpointer user_data) +{ + GList **list = (GList **) user_data; + + *list = g_list_prepend (*list, (gpointer) info); + return TRUE; +} + +static GList * +lookup_object_info (GObject *object) +{ + GList *info_list = NULL; + + foreach_object_info (object, lookup_object_info_cb, &info_list); + return info_list; } +typedef struct { + const char *iface; + const DBusGObjectInfo *info; + gboolean fallback; + GType iface_type; +} LookupObjectInfoByIfaceData; + +static gboolean +lookup_object_info_by_iface_cb (const DBusGObjectInfo *info, + GType gtype, + gpointer user_data) +{ + LookupObjectInfoByIfaceData *lookup_data = (LookupObjectInfoByIfaceData *) user_data; + + /* If interface is not specified, choose the first info */ + if (lookup_data->fallback && (!lookup_data->iface || strlen (lookup_data->iface) == 0)) + { + lookup_data->info = info; + lookup_data->iface_type = gtype; + } + else if (info->exported_properties && !strcmp (info->exported_properties, lookup_data->iface)) + { + lookup_data->info = info; + lookup_data->iface_type = gtype; + } + + return !lookup_data->info; +} + +static const DBusGObjectInfo * +lookup_object_info_by_iface (GObject *object, + const char *iface, + gboolean fallback, + GType *out_iface_type) +{ + LookupObjectInfoByIfaceData data; + + data.iface = iface; + data.info = NULL; + data.fallback = fallback; + data.iface_type = 0; + + foreach_object_info (object, lookup_object_info_by_iface_cb, &data); + + if (out_iface_type && data.info) + *out_iface_type = data.iface_type; + + return data.info; +} + static void gobject_unregister_function (DBusConnection *connection, void *user_data) @@ -443,30 +642,41 @@ write_interface (gpointer key, gpointer val, gpointer user_data) for (; properties; properties = properties->next) { + const char *iface; const char *propname; + const char *propname_uscore; + const char *access_type; GParamSpec *spec; char *dbus_type; gboolean can_set; gboolean can_get; char *s; - propname = properties->data; spec = NULL; - s = _dbus_gutils_wincaps_to_uscore (propname); + property_iterate (properties->data, object_info->format_version, &iface, &propname, &propname_uscore, &access_type); - spec = g_object_class_find_property (g_type_class_peek (data->gtype), s); + if (!propname_uscore) + { + char *s = _dbus_gutils_wincaps_to_uscore (propname); + spec = g_object_class_find_property (g_type_class_peek (data->gtype), s); + g_free (s); + } + else + { + spec = g_object_class_find_property (g_type_class_peek (data->gtype), propname_uscore); + } g_assert (spec != NULL); - g_free (s); - + dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec)); g_assert (dbus_type != NULL); - - can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && - (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); - + + can_set = strcmp (access_type, "readwrite") == 0 + && ((spec->flags & G_PARAM_WRITABLE) != 0 + && (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); + can_get = (spec->flags & G_PARAM_READABLE) != 0; - + if (can_set || can_get) { g_string_append_printf (xml, " <property name=\"%s\" ", propname); @@ -486,10 +696,8 @@ write_interface (gpointer key, gpointer val, gpointer user_data) g_string_append (xml, "\"/>\n"); } - - g_free (dbus_type); - g_string_append (xml, " </property>\n"); + g_free (dbus_type); } g_slist_free (values->properties); @@ -556,7 +764,7 @@ introspect_interfaces (GObject *object, GString *xml) const char *iface; const char *signame; - propsig = propsig_iterate (propsig, &iface, &signame); + propsig = signal_iterate (propsig, &iface, &signame); values = lookup_values (interfaces, iface); values->signals = g_slist_prepend (values->signals, (gpointer) signame); @@ -567,13 +775,15 @@ introspect_interfaces (GObject *object, GString *xml) { const char *iface; const char *propname; + const char *propname_uscore; + const char *access_type; - propsig = propsig_iterate (propsig, &iface, &propname); + propsig = property_iterate (propsig, info->format_version, &iface, &propname, &propname_uscore, &access_type); values = lookup_values (interfaces, iface); - values->properties = g_slist_prepend (values->properties, (gpointer) propname); + values->properties = g_slist_prepend (values->properties, (gpointer)iface); } - + memset (&data, 0, sizeof (data)); data.xml = xml; data.gtype = G_TYPE_FROM_INSTANCE (object); @@ -1271,6 +1481,70 @@ invoke_object_method (GObject *object, goto done; } +static gboolean +check_property_access (DBusConnection *connection, + DBusMessage *message, + GObject *object, + const char *wincaps_propiface, + const char *requested_propname, + const char *uscore_propname, + gboolean is_set) +{ + const DBusGObjectInfo *object_info; + const char *access_type; + DBusMessage *ret; + + if (!is_set && !disable_legacy_property_access) + return TRUE; + + object_info = lookup_object_info_by_iface (object, wincaps_propiface, TRUE, NULL); + if (!object_info) + { + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_ACCESS_DENIED, + "Interface \"%s\" isn't exported (or may not exist), can't access property \"%s\"", + wincaps_propiface, + requested_propname); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return FALSE; + } + + /* Try both forms of property names: "foo_bar" or "FooBar"; for historical + * reasons we accept both. + */ + if (object_info + && !(property_info_from_object_info (object_info, wincaps_propiface, requested_propname, &access_type) + || property_info_from_object_info (object_info, wincaps_propiface, uscore_propname, &access_type))) + { + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_ACCESS_DENIED, + "Property \"%s\" of interface \"%s\" isn't exported (or may not exist)", + requested_propname, + wincaps_propiface); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return FALSE; + } + + if (strcmp (access_type, "readwrite") == 0) + return TRUE; + else if (is_set ? strcmp (access_type, "read") == 0 + : strcmp (access_type, "write") == 0) + { + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_ACCESS_DENIED, + "Property \"%s\" of interface \"%s\" is not %s", + requested_propname, + wincaps_propiface, + is_set ? "settable" : "readable"); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + return FALSE; + } + return TRUE; +} + static DBusHandlerResult gobject_message_function (DBusConnection *connection, DBusMessage *message, @@ -1281,8 +1555,8 @@ gobject_message_function (DBusConnection *connection, gboolean setter; gboolean getter; char *s; - const char *wincaps_propname; - /* const char *wincaps_propiface; */ + const char *requested_propname; + const char *wincaps_propiface; DBusMessageIter iter; const DBusGMethodInfo *method; const DBusGObjectInfo *object_info; @@ -1299,7 +1573,8 @@ gobject_message_function (DBusConnection *connection, return invoke_object_method (object, object_info, method, connection, message); /* If no metainfo, we can still do properties and signals - * via standard GLib introspection + * via standard GLib introspection. Note we do now check + * property access against the metainfo if available. */ getter = FALSE; setter = FALSE; @@ -1322,10 +1597,8 @@ gobject_message_function (DBusConnection *connection, g_warning ("Property get or set does not have an interface string as first arg\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - /* We never use the interface name; if we did, we'd need to - * remember that it can be empty string for "pick one for me" - */ - /* dbus_message_iter_get_basic (&iter, &wincaps_propiface); */ + + dbus_message_iter_get_basic (&iter, &wincaps_propiface); dbus_message_iter_next (&iter); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) @@ -1333,13 +1606,19 @@ gobject_message_function (DBusConnection *connection, g_warning ("Property get or set does not have a property name string as second arg\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - dbus_message_iter_get_basic (&iter, &wincaps_propname); + + dbus_message_iter_get_basic (&iter, &requested_propname); dbus_message_iter_next (&iter); - - s = _dbus_gutils_wincaps_to_uscore (wincaps_propname); - pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), - s); + s = _dbus_gutils_wincaps_to_uscore (requested_propname); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), s); + + if (!check_property_access (connection, message, object, wincaps_propiface, requested_propname, s, setter)) + { + g_free (s); + return DBUS_HANDLER_RESULT_HANDLED; + } g_free (s); @@ -1364,11 +1643,6 @@ gobject_message_function (DBusConnection *connection, ret = get_object_property (connection, message, object, pspec); } - else - { - g_assert_not_reached (); - ret = NULL; - } g_assert (ret != NULL); @@ -1379,6 +1653,16 @@ gobject_message_function (DBusConnection *connection, dbus_message_unref (ret); return DBUS_HANDLER_RESULT_HANDLED; } + else + { + DBusMessage *ret; + + ret = dbus_message_new_error_printf (message, + DBUS_ERROR_INVALID_ARGS, + "No such property %s", requested_propname); + dbus_connection_send (connection, ret, NULL); + dbus_message_unref (ret); + } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1497,8 +1781,8 @@ export_signals (DBusGConnection *connection, const GList *info_list, GObject *ob GClosure *closure; char *s; - sigdata = propsig_iterate (sigdata, &iface, &signame); - + sigdata = signal_iterate (sigdata, &iface, &signame); + s = _dbus_gutils_wincaps_to_uscore (signame); id = g_signal_lookup (s, gtype); @@ -1657,6 +1941,32 @@ dbus_g_error_info_free (gpointer p) */ /** + * dbus_glib_global_set_disable_legacy_property_access: + * + * Historically, DBus-GLib allowed read/write access to any property + * regardless of the access flags specified in the introspection XML, + * and regardless of the DBus interface given. + * + * As of version 0.88, DBus-GLib by default allows read-only access to + * every GObject property of an object exported to the bus, regardless + * of whether or not the property is listed in the type info installed + * with dbus_g_object_type_install_info() and regardless of whether + * the correct interface is specified. Write access is denied. + * + * After calling this method, it will be required that the property is + * exported on the given interface, and even read-only access will be + * checked. This method changes behavior globally for the entire + * process. + * + * Since: 0.88 + */ +void +dbus_glib_global_set_disable_legacy_property_access (void) +{ + disable_legacy_property_access = TRUE; +} + +/** * dbus_g_object_type_install_info: * @object_type: #GType for the object * @info: introspection data generated by #dbus-glib-tool @@ -2310,23 +2620,23 @@ _dbus_gobject_test (const char *test_data_dir) sigdata = dbus_glib_internal_test_object_info.exported_signals; g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject")); g_assert (!strcmp (signame, "Frobnicate")); g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject")); g_assert (!strcmp (signame, "Sig0")); g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject")); g_assert (!strcmp (signame, "Sig1")); g_assert (*sigdata != '\0'); - sigdata = propsig_iterate (sigdata, &iface, &signame); + sigdata = signal_iterate (sigdata, &iface, &signame); g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject")); g_assert (!strcmp (signame, "Sig2")); g_assert (*sigdata == '\0'); - + i = 0; while (i < (int) G_N_ELEMENTS (name_pairs)) diff --git a/test/core/Makefile.am b/test/core/Makefile.am index 7ffda78..6216afe 100644 --- a/test/core/Makefile.am +++ b/test/core/Makefile.am @@ -50,7 +50,9 @@ BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h my-object- test_service_glib_SOURCES= \ my-object-marshal.c \ - test-service-glib.c + my-object.c \ + my-object.h \ + test-service-glib.c test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/dbus/dbus-binding-tool $(top_builddir)/dbus/dbus-binding-tool --prefix=my_object --mode=glib-server --output=test-service-glib-glue.h $(srcdir)/test-service-glib.xml diff --git a/test/core/my-object.c b/test/core/my-object.c new file mode 100644 index 0000000..a633b05 --- /dev/null +++ b/test/core/my-object.c @@ -0,0 +1,853 @@ +#include <config.h> +#include <string.h> +#include <glib/gi18n.h> +#include <glib-object.h> +#include "my-object.h" +#include "my-object-marshal.h" + +#include "test-service-glib-glue.h" + +/* Properties */ +enum +{ + PROP_0, + PROP_THIS_IS_A_STRING, + PROP_NO_TOUCHING, + PROP_SUPER_STUDLY, + PROP_SHOULD_BE_HIDDEN +}; + +enum +{ + FROBNICATE, + SIG0, + SIG1, + SIG2, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT) + +static void +my_object_finalize (GObject *object) +{ + MyObject *mobject = MY_OBJECT (object); + + g_free (mobject->this_is_a_string); + + (G_OBJECT_CLASS (my_object_parent_class)->finalize) (object); +} + +static void +my_object_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MyObject *mobject; + + mobject = MY_OBJECT (object); + + switch (prop_id) + { + case PROP_THIS_IS_A_STRING: + g_free (mobject->this_is_a_string); + mobject->this_is_a_string = g_value_dup_string (value); + break; + + case PROP_NO_TOUCHING: + mobject->notouching = g_value_get_uint (value); + break; + + case PROP_SUPER_STUDLY: + mobject->super_studly = g_value_get_double (value); + break; + + case PROP_SHOULD_BE_HIDDEN: + mobject->should_be_hidden = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +my_object_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MyObject *mobject; + + mobject = MY_OBJECT (object); + + switch (prop_id) + { + case PROP_THIS_IS_A_STRING: + g_value_set_string (value, mobject->this_is_a_string); + break; + + case PROP_NO_TOUCHING: + g_value_set_uint (value, mobject->notouching); + break; + + case PROP_SUPER_STUDLY: + g_value_set_double (value, mobject->super_studly); + break; + + case PROP_SHOULD_BE_HIDDEN: + g_value_set_boolean (value, mobject->should_be_hidden); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +my_object_init (MyObject *obj) +{ + obj->val = 0; + obj->notouching = 42; +} + +static void +my_object_class_init (MyObjectClass *mobject_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (mobject_class); + + dbus_g_object_type_install_info (MY_TYPE_OBJECT, + &dbus_glib_my_object_object_info); + + gobject_class->finalize = my_object_finalize; + gobject_class->set_property = my_object_set_property; + gobject_class->get_property = my_object_get_property; + + g_object_class_install_property (gobject_class, + PROP_THIS_IS_A_STRING, + g_param_spec_string ("this_is_a_string", + _("Sample string"), + _("Example of a string property"), + "default value", + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_NO_TOUCHING, + g_param_spec_uint ("no_touching", + _("Don't touch"), + _("Example of a readonly property (for export)"), + 0, 100, 42, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SUPER_STUDLY, + g_param_spec_double ("super-studly", + _("In Studly Caps"), + _("Example of a StudlyCaps property"), + 0, 256, 128, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_SHOULD_BE_HIDDEN, + g_param_spec_boolean ("should-be-hidden", + _("A non-exported property"), + _("Example of a property we don't want exported"), + FALSE, + G_PARAM_READWRITE)); + + signals[FROBNICATE] = + g_signal_new ("frobnicate", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + signals[SIG0] = + g_signal_new ("sig0", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + my_object_marshal_VOID__STRING_INT_STRING, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING); + + signals[SIG1] = + g_signal_new ("sig1", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + my_object_marshal_VOID__STRING_BOXED, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VALUE); + + signals[SIG2] = + g_signal_new ("sig2", + G_OBJECT_CLASS_TYPE (mobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, DBUS_TYPE_G_STRING_STRING_HASHTABLE); +} + +GQuark +my_object_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("my_object_error"); + + return quark; +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +my_object_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) + { + static const GEnumValue values[] = + { + + ENUM_ENTRY (MY_OBJECT_ERROR_FOO, "Foo"), + ENUM_ENTRY (MY_OBJECT_ERROR_BAR, "Bar"), + ENUM_ENTRY (MY_OBJECT_ERROR_MULTI_WORD, "Multi-word"), + { 0, 0, 0 } + }; + + etype = g_enum_register_static ("MyObjectError", values); + } + + return etype; +} + +gboolean +my_object_do_nothing (MyObject *obj, GError **error) +{ + return TRUE; +} + +gboolean +my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error) +{ + *ret = x +1; + return TRUE; +} + +gint32 +my_object_increment_retval (MyObject *obj, gint32 x) +{ + return x + 1; +} + +gint32 +my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) +{ + if (x + 1 > 10) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "%s", + "x is bigger than 9"); + return FALSE; + } + return x + 1; +} + +gboolean +my_object_throw_error (MyObject *obj, GError **error) +{ + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "%s", + "this method always loses"); + return FALSE; +} + +gboolean +my_object_throw_not_supported (MyObject *obj, GError **error) +{ + g_set_error (error, + DBUS_GERROR, + DBUS_GERROR_NOT_SUPPORTED, + "%s", + "this method always loses"); + return FALSE; +} + +gboolean +my_object_throw_error_multi_word (MyObject *obj, GError **error) +{ + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_MULTI_WORD, + "%s", + "this method's error has a hyphen"); + return FALSE; +} + +gboolean +my_object_throw_unregistered_error (MyObject *obj, GError **error) +{ + /* Unregistered errors shouldn't cause a dbus abort. See + * https://bugzilla.redhat.com/show_bug.cgi?id=581794 + */ + g_set_error (error, 0, 0, + "%s", + "this method always loses more"); + return FALSE; +} + + +gboolean +my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error) +{ + *ret = g_ascii_strup (str, -1); + return TRUE; +} + +gboolean +my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error) +{ + *d_ret = trouble + (x * 2); + *str_ret = g_ascii_strup (str, -1); + return TRUE; +} + +gboolean +my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error) +{ + *arg0 = 42; + *arg1 = g_strdup ("42"); + *arg2 = -67; + *arg3 = 2; + *arg4 = 26; + *arg5 = "hello world"; /* Annotation specifies as const */ + return TRUE; +} + +gboolean +my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error) +{ + GValue valstr = {0, }; + + g_value_init (&valstr, G_TYPE_STRING); + if (!g_value_transform (value, &valstr)) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "couldn't transform value"); + return FALSE; + } + *ret = g_value_dup_string (&valstr); + g_value_unset (&valstr); + return TRUE; +} + +gboolean +my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error) +{ + if (str[0] == '\0' || !g_ascii_isdigit (str[0])) { + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, str); + } else { + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, (int) g_ascii_strtoull (str, NULL, 10)); + } + return TRUE; +} + +gboolean +my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error) +{ + *len_ret = array->len; + return TRUE; +} + +gboolean +my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **ret, GError **error) +{ + guint32 val; + GArray *array; + + array = g_array_new (FALSE, TRUE, sizeof (guint32)); + + while (reqlen > 0) { + val = 42; + g_array_append_val (array, val); + val = 26; + g_array_append_val (array, val); + reqlen--; + } + val = 2; + g_array_append_val (array, val); + *ret = array; + return TRUE; +} + +gboolean +my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error) +{ + int len; + int i; + + len = g_strv_length ((char**) in); + + *out = g_new0 (char *, len + 1); + for (i = 0; i < len; i++) + { + (*out)[i] = g_ascii_strup (in[i], -1); + } + (*out)[i] = NULL; + + return TRUE; +} + +static void +hash_foreach_stringify (gpointer key, gpointer val, gpointer user_data) +{ + const char *keystr = key; + const GValue *value = val; + GValue *sval; + GHashTable *ret = user_data; + + sval = g_new0 (GValue, 1); + g_value_init (sval, G_TYPE_STRING); + if (!g_value_transform (value, sval)) + g_assert_not_reached (); + + g_hash_table_insert (ret, g_strdup (keystr), sval); +} + +static void +unset_and_free_gvalue (gpointer val) +{ + g_value_unset (val); + g_free (val); +} + +gboolean +my_object_many_stringify (MyObject *obj, GHashTable /* char * -> GValue * */ *vals, GHashTable /* char * -> GValue * */ **ret, GError **error) +{ + *ret = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, unset_and_free_gvalue); + g_hash_table_foreach (vals, hash_foreach_stringify, *ret); + return TRUE; +} + +gboolean +my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error) +{ + char **strs; + GArray *ints; + guint v_UINT; + + if (in->len != 2) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid array len"); + return FALSE; + } + + strs = g_ptr_array_index (in, 0); + if (!*strs || strcmp (*strs, "foo")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 0"); + return FALSE; + } + strs++; + if (!*strs || strcmp (*strs, "bar")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 1"); + return FALSE; + } + strs++; + if (*strs) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string array len in pos 0"); + return FALSE; + } + strs = g_ptr_array_index (in, 1); + if (!*strs || strcmp (*strs, "baz")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 0"); + return FALSE; + } + strs++; + if (!*strs || strcmp (*strs, "whee")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 1"); + return FALSE; + } + strs++; + if (!*strs || strcmp (*strs, "moo")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string 2"); + return FALSE; + } + strs++; + if (*strs) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid string array len in pos 1"); + return FALSE; + } + + *ret = g_ptr_array_new (); + + ints = g_array_new (TRUE, TRUE, sizeof (guint)); + v_UINT = 10; + g_array_append_val (ints, v_UINT); + v_UINT = 42; + g_array_append_val (ints, v_UINT); + v_UINT = 27; + g_array_append_val (ints, v_UINT); + g_ptr_array_add (*ret, ints); + + ints = g_array_new (TRUE, TRUE, sizeof (guint)); + v_UINT = 30; + g_array_append_val (ints, v_UINT); + g_ptr_array_add (*ret, ints); + return TRUE; +} + +gboolean +my_object_objpath (MyObject *obj, const char *incoming, const char **outgoing, GError **error) +{ + if (strcmp (incoming, "/org/freedesktop/DBus/GLib/Tests/MyTestObject")) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid incoming object"); + return FALSE; + } + *outgoing = "/org/freedesktop/DBus/GLib/Tests/MyTestObject2"; + return TRUE; +} + +gboolean +my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error) +{ + *objs = g_ptr_array_new (); + + g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject")); + g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); + + return TRUE; +} + +static void +hash_foreach (gpointer key, gpointer val, gpointer user_data) +{ + const char *keystr = key; + const char *valstr = val; + guint *count = user_data; + + *count += (strlen (keystr) + strlen (valstr)); + g_print ("%s -> %s\n", keystr, valstr); +} + +gboolean +my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error) +{ + *len = 0; + g_hash_table_foreach (table, hash_foreach, len); + return TRUE; +} + +gboolean +my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error) +{ + if (invals->n_values != 3 + || G_VALUE_TYPE (g_value_array_get_nth (invals, 0)) != G_TYPE_STRING + || G_VALUE_TYPE (g_value_array_get_nth (invals, 1)) != G_TYPE_UINT + || G_VALUE_TYPE (g_value_array_get_nth (invals, 2)) != G_TYPE_VALUE) + { + g_set_error (error, + MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "invalid incoming values"); + return FALSE; + } + *outvals = g_value_array_new (2); + g_value_array_append (*outvals, NULL); + g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), + g_value_get_uint (g_value_array_get_nth (invals, 1)) + 1); + g_value_array_append (*outvals, NULL); + g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), DBUS_TYPE_G_OBJECT_PATH); + g_value_set_boxed (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), + g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); + return TRUE; +} + +gboolean +my_object_get_hash (MyObject *obj, GHashTable **ret, GError **error) +{ + GHashTable *table; + + table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (table, "foo", "bar"); + g_hash_table_insert (table, "baz", "whee"); + g_hash_table_insert (table, "cow", "crack"); + *ret = table; + return TRUE; +} + +gboolean +my_object_increment_val (MyObject *obj, GError **error) +{ + obj->val++; + return TRUE; +} + +gboolean +my_object_get_val (MyObject *obj, guint *ret, GError **error) +{ + *ret = obj->val; + return TRUE; +} + +gboolean +my_object_get_value (MyObject *obj, guint *ret, GError **error) +{ + *ret = obj->val; + return TRUE; +} + +gboolean +my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error) +{ + GType t; + t = G_VALUE_TYPE(variant); + g_value_init (ret, t); + g_value_copy (variant, ret); + + return TRUE; +} + +gboolean +my_object_echo_signature (MyObject *obj, const gchar *in, gchar **out, GError **error) +{ + *out = g_strdup (in); + return TRUE; +} + +gboolean +my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error) +{ + GArray *array; + int i; + int j; + + j = 0; + + array = (GArray *)g_value_get_boxed (variant); + + for (i = 0; i <= 2; i++) + { + j = g_array_index (array, int, i); + if (j != i + 1) + goto error; + } + + return TRUE; + +error: + *error = g_error_new (MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "Error decoding a variant of type ai (i + 1 = %i, j = %i)", + i, j + 1); + return FALSE; +} + + +typedef struct _HashAndString HashAndString; + +struct _HashAndString +{ + GHashTable *hash; + gchar* string; +}; + +static void +hash_foreach_prepend_string (gpointer key, gpointer val, gpointer user_data) +{ + HashAndString *data = (HashAndString*) user_data; + gchar *in = (gchar*) val; + g_hash_table_insert (data->hash, g_strdup ((gchar*) key), + g_strjoin (" ", data->string, in, NULL)); +} + + +static void +hash_foreach_mangle_dict_of_strings (gpointer key, gpointer val, gpointer user_data) +{ + GHashTable *out = (GHashTable*) user_data; + GHashTable *in_dict = (GHashTable *) val; + HashAndString *data = g_new0 (HashAndString, 1); + + data->string = (gchar*) key; + data->hash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_foreach (in_dict, hash_foreach_prepend_string, data); + + g_hash_table_insert(out, g_strdup ((gchar*) key), data->hash); +} + +gboolean +my_object_dict_of_dicts (MyObject *obj, GHashTable *in, + GHashTable **out, GError **error) +{ + *out = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_hash_table_destroy); + g_hash_table_foreach (in, hash_foreach_mangle_dict_of_strings, *out); + return TRUE; +} + +void +my_object_dict_of_sigs (MyObject *obj, + GHashTable *dict, + DBusGMethodInvocation *context) +{ + dbus_g_method_return (context, dict); +} + +void +my_object_dict_of_objs (MyObject *obj, + GHashTable *dict, + DBusGMethodInvocation *context) +{ + dbus_g_method_return (context, dict); +} + +gboolean +my_object_emit_frobnicate (MyObject *obj, GError **error) +{ + g_signal_emit (obj, signals[FROBNICATE], 0, 42); + return TRUE; +} + +gboolean +my_object_emit_signals (MyObject *obj, GError **error) +{ + GValue val = {0, }; + + g_signal_emit (obj, signals[SIG0], 0, "foo", 22, "moo"); + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, "bar"); + g_signal_emit (obj, signals[SIG1], 0, "baz", &val); + g_value_unset (&val); + + return TRUE; +} + +gboolean +my_object_emit_signal2 (MyObject *obj, GError **error) +{ + GHashTable *table; + + table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (table, "baz", "cow"); + g_hash_table_insert (table, "bar", "foo"); + g_signal_emit (obj, signals[SIG2], 0, table); + g_hash_table_destroy (table); + return TRUE; +} + +typedef struct { + gint32 x; + DBusGMethodInvocation *context; +} IncrementData; + +static gboolean +do_async_increment (IncrementData *data) +{ + gint32 newx = data->x + 1; + dbus_g_method_return (data->context, newx); + g_free (data); + return FALSE; +} + +void +my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context) +{ + IncrementData *data = g_new0 (IncrementData, 1); + data->x = x; + data->context = context; + g_idle_add ((GSourceFunc)do_async_increment, data); +} + +static gboolean +do_async_error (IncrementData *data) +{ + GError *error; + error = g_error_new (MY_OBJECT_ERROR, + MY_OBJECT_ERROR_FOO, + "%s", + "this method always loses"); + dbus_g_method_return_error (data->context, error); + g_free (data); + return FALSE; +} + +void +my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context) +{ + IncrementData *data = g_new0(IncrementData, 1); + data->context = context; + g_idle_add ((GSourceFunc)do_async_error, data); +} + +extern GMainLoop *loop; + +gboolean +my_object_terminate (MyObject *obj, GError **error) +{ + g_main_loop_quit (loop); + return TRUE; +} + +void +my_object_unsafe_disable_legacy_property_access (MyObject *obj) +{ + dbus_glib_global_set_disable_legacy_property_access (); +} diff --git a/test/core/my-object.h b/test/core/my-object.h new file mode 100644 index 0000000..28f8704 --- /dev/null +++ b/test/core/my-object.h @@ -0,0 +1,118 @@ +#ifndef __MY_OBJECT_H__ +#define __MY_OBJECT_H__ + +#include <glib-object.h> +#include <dbus/dbus-glib.h> + +typedef struct MyObject MyObject; +typedef struct MyObjectClass MyObjectClass; + +GType my_object_get_type (void); + +struct MyObject +{ + GObject parent; + char *this_is_a_string; + guint notouching; + guint val; + gdouble super_studly; + gboolean should_be_hidden; +}; + +struct MyObjectClass +{ + GObjectClass parent; +}; + +#define MY_TYPE_OBJECT (my_object_get_type ()) +#define MY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MY_TYPE_OBJECT, MyObject)) +#define MY_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_OBJECT, MyObjectClass)) +#define MY_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MY_TYPE_OBJECT)) +#define MY_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_OBJECT)) +#define MY_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_OBJECT, MyObjectClass)) + +typedef enum +{ + MY_OBJECT_ERROR_FOO, + MY_OBJECT_ERROR_BAR, + MY_OBJECT_ERROR_MULTI_WORD +} MyObjectError; + +#define MY_OBJECT_ERROR (my_object_error_quark ()) +#define MY_TYPE_ERROR (my_object_error_get_type ()) + +GQuark my_object_error_quark (void); +GType my_object_error_get_type (void); + +gboolean my_object_do_nothing (MyObject *obj, GError **error); + +gboolean my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); + +gint32 my_object_increment_retval (MyObject *obj, gint32 x); + +gint32 my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error); + +gboolean my_object_throw_error (MyObject *obj, GError **error); +gboolean my_object_throw_not_supported (MyObject *obj, GError **error); +gboolean my_object_throw_error_multi_word (MyObject *obj, GError **error); +gboolean my_object_throw_unregistered_error (MyObject *obj, GError **error); + +gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error); + +gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error); + +gboolean my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error); + +gboolean my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error); +gboolean my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **array, GError **error); + +gboolean my_object_many_stringify (MyObject *obj, GHashTable *vals, GHashTable **ret, GError **error); + +gboolean my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error); + +gboolean my_object_objpath (MyObject *obj, const char *in, const char **arg1, GError **error); + +gboolean my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error); + +gboolean my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error); +gboolean my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error); + +gboolean my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error); + +gboolean my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error); + +gboolean my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error); + +gboolean my_object_get_hash (MyObject *obj, GHashTable **table, GError **error); + +gboolean my_object_increment_val (MyObject *obj, GError **error); + +gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error); + +gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error); + +gboolean my_object_emit_signals (MyObject *obj, GError **error); +gboolean my_object_emit_signal2 (MyObject *obj, GError **error); + +gboolean my_object_emit_frobnicate (MyObject *obj, GError **error); + +gboolean my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error); +gboolean my_object_echo_signature (MyObject *obj, const gchar *in, gchar **out, GError **error); + +gboolean my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error); + +gboolean my_object_dict_of_dicts (MyObject *obj, GHashTable *dict, GHashTable **ret, GError **error); + +void my_object_dict_of_sigs (MyObject *obj, GHashTable *dict, DBusGMethodInvocation *ctx); + +void my_object_dict_of_objs (MyObject *obj, GHashTable *dict, DBusGMethodInvocation *ctx); + +gboolean my_object_terminate (MyObject *obj, GError **error); + +void my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context); + +void my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context); + +void my_object_unsafe_disable_legacy_property_access (MyObject *obj); + +#endif diff --git a/test/core/test-dbus-glib.c b/test/core/test-dbus-glib.c index f32b2d4..d78ce58 100644 --- a/test/core/test-dbus-glib.c +++ b/test/core/test-dbus-glib.c @@ -268,7 +268,6 @@ increment_async_cb (DBusGProxy *proxy, guint val, GError *error, gpointer data) g_source_remove (exit_timeout); } - static void lose (const char *str, ...) { @@ -313,6 +312,7 @@ main (int argc, char **argv) DBusGProxy *driver; DBusGProxy *proxy; DBusGProxy *proxy2; + DBusGProxy *property_proxy; char **name_list; guint name_list_len; guint i; @@ -1577,7 +1577,10 @@ main (int argc, char **argv) node = description_load_from_string (v_STRING_2, strlen (v_STRING_2), &error); if (!node) - lose_gerror ("Failed to parse introspection data: %s", error); + { + g_printerr ("===\n%s\n===\n", v_STRING_2); + lose_gerror ("Failed to parse introspection data: %s", error); + } found_introspectable = FALSE; found_properties = FALSE; @@ -1595,9 +1598,10 @@ main (int argc, char **argv) { GSList *elt; gboolean found_manyargs; - + gboolean found_no_touching = FALSE; + found_myobject = TRUE; - + found_manyargs = FALSE; for (elt = interface_info_get_methods (iface); elt; elt = elt->next) { @@ -1612,6 +1616,23 @@ main (int argc, char **argv) } if (!found_manyargs) lose ("Missing method org.freedesktop.DBus.GLib.Tests.MyObject.ManyArgs"); + for (elt = interface_info_get_properties (iface); elt; elt = elt->next) + { + PropertyInfo *prop = elt->data; + + if (strcmp (property_info_get_name (prop), "no-touching") == 0) + { + if (property_info_get_access (prop) != PROPERTY_READ) + lose ("property no-touching had incorrect access %d", property_info_get_access (prop)); + else + { + found_no_touching = TRUE; + break; + } + } + } + if (!found_no_touching) + lose ("didn't find property \"no-touching\" in org.freedesktop.DBus.GLib.Tests.MyObject"); } else if (!found_fooobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.GLib.Tests.FooObject") == 0) found_fooobject = TRUE; @@ -1623,7 +1644,262 @@ main (int argc, char **argv) lose ("Missing interface"); } g_free (v_STRING_2); - + + /* Properties tests */ + property_proxy = dbus_g_proxy_new_from_proxy (proxy, DBUS_INTERFACE_PROPERTIES, NULL); + g_object_unref (proxy); + proxy = NULL; + + g_print ("Calling GetProperty (1)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "this_is_a_string", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_STRING)); + g_assert (!strcmp (g_value_get_string (&value), "")); + g_value_unset (&value); + } + + g_print ("Calling SetProperty (1)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, "testing value"); + if (!dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "this_is_a_string", + G_TYPE_VALUE, &value, G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to complete SetProperty call", error); + g_value_unset (&value); + } + + g_print ("Calling GetProperty of read-only property\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "no-touching", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty no-touching call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_UINT)); + g_assert (g_value_get_uint (&value) == 42); + g_value_unset (&value); + } + + g_print ("Calling SetProperty (1)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_UINT); + g_value_set_uint (&value, 40); + if (dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "no-touching", + G_TYPE_VALUE, &value, G_TYPE_INVALID, G_TYPE_INVALID)) + lose ("Unexpected success from SetProperty call for read-only value \"no-touching\""); + g_clear_error (&error); + g_value_unset (&value); + } + + g_print ("Calling GetProperty of read-only property (again)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "no-touching", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_UINT)); + g_assert (g_value_get_uint (&value) == 42); + g_value_unset (&value); + } + + g_print ("Calling GetProperty (2)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "this_is_a_string", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_STRING)); + g_assert (!strcmp (g_value_get_string (&value), "testing value")); + g_value_unset (&value); + } + + g_print ("Calling GetProperty: SuperStudly\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "SuperStudly", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)); + g_value_unset (&value); + } + + g_print ("Calling GetProperty: super-studly\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "super-studly", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)); + g_value_unset (&value); + } + + g_print ("Calling GetProperty: super_studly\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "super_studly", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed to complete GetProperty call", error); + g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)); + g_value_unset (&value); + } + + g_print ("Calling GetProperty on unknown property\n"); + { + GValue value = {0,}; + if (dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "SomeUnknownProperty", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose ("Unexpected success for GetProperty call of unknown property"); + + g_clear_error (&error); + } + + /* These two are expected to pass unless we call disable_legacy_property_access */ + + g_print ("Calling GetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed GetProperty call of \"should-be-hidden\" property", error); + g_assert (G_VALUE_HOLDS_BOOLEAN (&value)); + g_assert (g_value_get_boolean (&value) == FALSE); + g_value_unset (&value); + } + + g_print ("Calling GetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "ShouldBeHidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed GetProperty call of \"ShouldBeHidden\" property", error); + + g_value_unset (&value); + } + + g_print ("Calling SetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, TRUE); + if (dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_VALUE, &value, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose ("Unexpected success from SetProperty call of \"should-be-hidden\" property"); + g_value_unset (&value); + g_clear_error (&error); + } + + g_print ("Calling GetProperty on not-exported property (legacy enabled)\n"); + { + GValue value = {0,}; + if (!dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose_gerror ("Failed GetProperty call of \"should-be-hidden\" property", error); + g_assert (G_VALUE_HOLDS_BOOLEAN (&value)); + g_assert (g_value_get_boolean (&value) == FALSE); + g_value_unset (&value); + } + + /* Now, call disable_legacy_property_access */ + + g_assert (proxy == NULL); + proxy = dbus_g_proxy_new_for_name_owner (connection, + "org.freedesktop.DBus.GLib.TestService", + "/org/freedesktop/DBus/GLib/Tests/MyTestObject", + "org.freedesktop.DBus.GLib.Tests.MyObject", + &error); + + if (!dbus_g_proxy_call (proxy, "UnsafeDisableLegacyPropertyAccess", &error, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to invoke UnsafeDisableLegacyPropertyAccess", error); + + g_object_unref (proxy); + proxy = NULL; + + g_print ("Calling GetProperty on not-exported property (legacy *disabled*)\n"); + { + GValue value = {0,}; + if (dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose ("Unexpected success from GetProperty call of \"should-be-hidden\" property"); + g_clear_error (&error); + } + + g_print ("Calling GetProperty on not-exported property (legacy *disabled*)\n"); + { + GValue value = {0,}; + if (dbus_g_proxy_call (property_proxy, "Get", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "ShouldBeHidden", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) + lose ("Unexpected success from GetProperty call of \"ShouldBeHidden\" property"); + g_clear_error (&error); + } + + g_print ("Calling SetProperty on not-exported property (legacy *disabled*)\n"); + { + GValue value = {0,}; + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, FALSE); + if (dbus_g_proxy_call (property_proxy, "Set", &error, + G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject", + G_TYPE_STRING, "should-be-hidden", + G_TYPE_VALUE, &value, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose ("Unexpected success from SetProperty call of \"should-be-hidden\" property"); + g_value_unset (&value); + g_clear_error (&error); + } + + g_object_unref (property_proxy); + property_proxy = NULL; test_terminate_proxy1 = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.GLib.TestService", diff --git a/test/core/test-service-glib.c b/test/core/test-service-glib.c index 222db17..bb9157e 100644 --- a/test/core/test-service-glib.c +++ b/test/core/test-service-glib.c @@ -10,837 +10,12 @@ #include <glib/gi18n.h> #include <glib-object.h> #include <glib/gquark.h> -#include "my-object-marshal.h" -typedef struct MyObject MyObject; -typedef struct MyObjectClass MyObjectClass; - -GType my_object_get_type (void); - -struct MyObject -{ - GObject parent; - char *this_is_a_string; - guint val; -}; - -struct MyObjectClass -{ - GObjectClass parent; -}; - -#define MY_TYPE_OBJECT (my_object_get_type ()) -#define MY_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MY_TYPE_OBJECT, MyObject)) -#define MY_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_OBJECT, MyObjectClass)) -#define MY_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MY_TYPE_OBJECT)) -#define MY_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_OBJECT)) -#define MY_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_OBJECT, MyObjectClass)) - -G_DEFINE_TYPE(MyObject, my_object, G_TYPE_OBJECT) - -typedef enum -{ - MY_OBJECT_ERROR_FOO, - MY_OBJECT_ERROR_BAR -} MyObjectError; - -#define MY_OBJECT_ERROR (my_object_error_quark ()) - -#define MY_TYPE_ERROR (my_object_error_get_type ()) - -gboolean my_object_do_nothing (MyObject *obj, GError **error); - -gboolean my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); - -gint32 my_object_increment_retval (MyObject *obj, gint32 x); - -gint32 my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error); - -gboolean my_object_throw_error (MyObject *obj, GError **error); - -gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error); - -gboolean my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error); - -gboolean my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error); - -gboolean my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error); -gboolean my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **array, GError **error); - -gboolean my_object_many_stringify (MyObject *obj, GHashTable *vals, GHashTable **ret, GError **error); - -gboolean my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error); - -gboolean my_object_objpath (MyObject *obj, const char *in, const char **arg1, GError **error); - -gboolean my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error); - -gboolean my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error); -gboolean my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error); - -gboolean my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error); - -gboolean my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error); - -gboolean my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error); - -gboolean my_object_get_hash (MyObject *obj, GHashTable **table, GError **error); - -gboolean my_object_increment_val (MyObject *obj, GError **error); - -gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error); - -gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error); - -gboolean my_object_emit_signals (MyObject *obj, GError **error); -gboolean my_object_emit_signal2 (MyObject *obj, GError **error); - -gboolean my_object_emit_frobnicate (MyObject *obj, GError **error); - -gboolean my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error); - -gboolean my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error); - -gboolean my_object_dict_of_dicts (MyObject *obj, GHashTable *dict, GHashTable **ret, GError **error); - -gboolean my_object_terminate (MyObject *obj, GError **error); - -void my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context); - -void my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context); - -#include "test-service-glib-glue.h" - -GQuark my_object_error_quark (void); - -GType my_object_error_get_type (void); - -/* Properties */ -enum -{ - PROP_0, - PROP_THIS_IS_A_STRING -}; - -enum -{ - FROBNICATE, - SIG0, - SIG1, - SIG2, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void -my_object_finalize (GObject *object) -{ - MyObject *mobject = MY_OBJECT (object); - - g_free (mobject->this_is_a_string); - - (G_OBJECT_CLASS (my_object_parent_class)->finalize) (object); -} - -static void -my_object_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MyObject *mobject; - - mobject = MY_OBJECT (object); - - switch (prop_id) - { - case PROP_THIS_IS_A_STRING: - g_free (mobject->this_is_a_string); - mobject->this_is_a_string = g_value_dup_string (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -my_object_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MyObject *mobject; - - mobject = MY_OBJECT (object); - - switch (prop_id) - { - case PROP_THIS_IS_A_STRING: - g_value_set_string (value, mobject->this_is_a_string); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -my_object_init (MyObject *obj) -{ - obj->val = 0; -} - -static void -my_object_class_init (MyObjectClass *mobject_class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (mobject_class); - - gobject_class->finalize = my_object_finalize; - gobject_class->set_property = my_object_set_property; - gobject_class->get_property = my_object_get_property; - - g_object_class_install_property (gobject_class, - PROP_THIS_IS_A_STRING, - g_param_spec_string ("this_is_a_string", - _("Sample string"), - _("Example of a string property"), - "default value", - G_PARAM_READWRITE)); - signals[FROBNICATE] = - g_signal_new ("frobnicate", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - signals[SIG0] = - g_signal_new ("sig0", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - my_object_marshal_VOID__STRING_INT_STRING, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING); - - signals[SIG1] = - g_signal_new ("sig1", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - my_object_marshal_VOID__STRING_BOXED, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VALUE); - - signals[SIG2] = - g_signal_new ("sig2", - G_OBJECT_CLASS_TYPE (mobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_STRING_STRING_HASHTABLE); -} - -GQuark -my_object_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("my_object_error"); - - return quark; -} - -/* This should really be standard. */ -#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } - -GType -my_object_error_get_type (void) -{ - static GType etype = 0; - - if (etype == 0) - { - static const GEnumValue values[] = - { - - ENUM_ENTRY (MY_OBJECT_ERROR_FOO, "Foo"), - ENUM_ENTRY (MY_OBJECT_ERROR_BAR, "Bar"), - { 0, 0, 0 } - }; - - etype = g_enum_register_static ("MyObjectError", values); - } - - return etype; -} +#include "my-object.h" static GObject *obj; static GObject *obj2; - -gboolean -my_object_do_nothing (MyObject *obj, GError **error) -{ - return TRUE; -} - -gboolean -my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error) -{ - *ret = x +1; - return TRUE; -} - -gint32 -my_object_increment_retval (MyObject *obj, gint32 x) -{ - return x + 1; -} - -gint32 -my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) -{ - if (x + 1 > 10) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "%s", - "x is bigger than 9"); - return FALSE; - } - return x + 1; -} - -gboolean -my_object_throw_error (MyObject *obj, GError **error) -{ - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "%s", - "this method always loses"); - return FALSE; -} - -gboolean -my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error) -{ - *ret = g_ascii_strup (str, -1); - return TRUE; -} - -gboolean -my_object_many_args (MyObject *obj, guint32 x, const char *str, double trouble, double *d_ret, char **str_ret, GError **error) -{ - *d_ret = trouble + (x * 2); - *str_ret = g_ascii_strup (str, -1); - return TRUE; -} - -gboolean -my_object_many_return (MyObject *obj, guint32 *arg0, char **arg1, gint32 *arg2, guint32 *arg3, guint32 *arg4, const char **arg5, GError **error) -{ - *arg0 = 42; - *arg1 = g_strdup ("42"); - *arg2 = -67; - *arg3 = 2; - *arg4 = 26; - *arg5 = "hello world"; /* Annotation specifies as const */ - return TRUE; -} - -gboolean -my_object_stringify (MyObject *obj, GValue *value, char **ret, GError **error) -{ - GValue valstr = {0, }; - - g_value_init (&valstr, G_TYPE_STRING); - if (!g_value_transform (value, &valstr)) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "couldn't transform value"); - return FALSE; - } - *ret = g_value_dup_string (&valstr); - g_value_unset (&valstr); - return TRUE; -} - -gboolean -my_object_unstringify (MyObject *obj, const char *str, GValue *value, GError **error) -{ - if (str[0] == '\0' || !g_ascii_isdigit (str[0])) { - g_value_init (value, G_TYPE_STRING); - g_value_set_string (value, str); - } else { - g_value_init (value, G_TYPE_INT); - g_value_set_int (value, (int) g_ascii_strtoull (str, NULL, 10)); - } - return TRUE; -} - -gboolean -my_object_recursive1 (MyObject *obj, GArray *array, guint32 *len_ret, GError **error) -{ - *len_ret = array->len; - return TRUE; -} - -gboolean -my_object_recursive2 (MyObject *obj, guint32 reqlen, GArray **ret, GError **error) -{ - guint32 val; - GArray *array; - - array = g_array_new (FALSE, TRUE, sizeof (guint32)); - - while (reqlen > 0) { - val = 42; - g_array_append_val (array, val); - val = 26; - g_array_append_val (array, val); - reqlen--; - } - val = 2; - g_array_append_val (array, val); - *ret = array; - return TRUE; -} - -gboolean -my_object_many_uppercase (MyObject *obj, const char * const *in, char ***out, GError **error) -{ - int len; - int i; - - len = g_strv_length ((char**) in); - - *out = g_new0 (char *, len + 1); - for (i = 0; i < len; i++) - { - (*out)[i] = g_ascii_strup (in[i], -1); - } - (*out)[i] = NULL; - - return TRUE; -} - -static void -hash_foreach_stringify (gpointer key, gpointer val, gpointer user_data) -{ - const char *keystr = key; - const GValue *value = val; - GValue *sval; - GHashTable *ret = user_data; - - sval = g_new0 (GValue, 1); - g_value_init (sval, G_TYPE_STRING); - if (!g_value_transform (value, sval)) - g_assert_not_reached (); - - g_hash_table_insert (ret, g_strdup (keystr), sval); -} - -static void -unset_and_free_gvalue (gpointer val) -{ - g_value_unset (val); - g_free (val); -} - -gboolean -my_object_many_stringify (MyObject *obj, GHashTable /* char * -> GValue * */ *vals, GHashTable /* char * -> GValue * */ **ret, GError **error) -{ - *ret = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, unset_and_free_gvalue); - g_hash_table_foreach (vals, hash_foreach_stringify, *ret); - return TRUE; -} - -gboolean -my_object_rec_arrays (MyObject *obj, GPtrArray *in, GPtrArray **ret, GError **error) -{ - char **strs; - GArray *ints; - guint v_UINT; - - if (in->len != 2) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid array len"); - return FALSE; - } - - strs = g_ptr_array_index (in, 0); - if (!*strs || strcmp (*strs, "foo")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 0"); - return FALSE; - } - strs++; - if (!*strs || strcmp (*strs, "bar")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 1"); - return FALSE; - } - strs++; - if (*strs) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string array len in pos 0"); - return FALSE; - } - strs = g_ptr_array_index (in, 1); - if (!*strs || strcmp (*strs, "baz")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 0"); - return FALSE; - } - strs++; - if (!*strs || strcmp (*strs, "whee")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 1"); - return FALSE; - } - strs++; - if (!*strs || strcmp (*strs, "moo")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string 2"); - return FALSE; - } - strs++; - if (*strs) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid string array len in pos 1"); - return FALSE; - } - - *ret = g_ptr_array_new (); - - ints = g_array_new (TRUE, TRUE, sizeof (guint)); - v_UINT = 10; - g_array_append_val (ints, v_UINT); - v_UINT = 42; - g_array_append_val (ints, v_UINT); - v_UINT = 27; - g_array_append_val (ints, v_UINT); - g_ptr_array_add (*ret, ints); - - ints = g_array_new (TRUE, TRUE, sizeof (guint)); - v_UINT = 30; - g_array_append_val (ints, v_UINT); - g_ptr_array_add (*ret, ints); - return TRUE; -} - -gboolean -my_object_objpath (MyObject *obj, const char *incoming, const char **outgoing, GError **error) -{ - if (strcmp (incoming, "/org/freedesktop/DBus/GLib/Tests/MyTestObject")) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid incoming object"); - return FALSE; - } - *outgoing = "/org/freedesktop/DBus/GLib/Tests/MyTestObject2"; - return TRUE; -} - -gboolean -my_object_get_objs (MyObject *obj, GPtrArray **objs, GError **error) -{ - *objs = g_ptr_array_new (); - - g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject")); - g_ptr_array_add (*objs, g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); - - return TRUE; -} - -static void -hash_foreach (gpointer key, gpointer val, gpointer user_data) -{ - const char *keystr = key; - const char *valstr = val; - guint *count = user_data; - - *count += (strlen (keystr) + strlen (valstr)); - g_print ("%s -> %s\n", keystr, valstr); -} - -gboolean -my_object_str_hash_len (MyObject *obj, GHashTable *table, guint *len, GError **error) -{ - *len = 0; - g_hash_table_foreach (table, hash_foreach, len); - return TRUE; -} - -gboolean -my_object_send_car (MyObject *obj, GValueArray *invals, GValueArray **outvals, GError **error) -{ - if (invals->n_values != 3 - || G_VALUE_TYPE (g_value_array_get_nth (invals, 0)) != G_TYPE_STRING - || G_VALUE_TYPE (g_value_array_get_nth (invals, 1)) != G_TYPE_UINT - || G_VALUE_TYPE (g_value_array_get_nth (invals, 2)) != G_TYPE_VALUE) - { - g_set_error (error, - MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "invalid incoming values"); - return FALSE; - } - *outvals = g_value_array_new (2); - g_value_array_append (*outvals, NULL); - g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), G_TYPE_UINT); - g_value_set_uint (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), - g_value_get_uint (g_value_array_get_nth (invals, 1)) + 1); - g_value_array_append (*outvals, NULL); - g_value_init (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), DBUS_TYPE_G_OBJECT_PATH); - g_value_set_boxed (g_value_array_get_nth (*outvals, (*outvals)->n_values - 1), - g_strdup ("/org/freedesktop/DBus/GLib/Tests/MyTestObject2")); - return TRUE; -} - -gboolean -my_object_get_hash (MyObject *obj, GHashTable **ret, GError **error) -{ - GHashTable *table; - - table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (table, "foo", "bar"); - g_hash_table_insert (table, "baz", "whee"); - g_hash_table_insert (table, "cow", "crack"); - *ret = table; - return TRUE; -} - -gboolean -my_object_increment_val (MyObject *obj, GError **error) -{ - obj->val++; - return TRUE; -} - -gboolean -my_object_get_val (MyObject *obj, guint *ret, GError **error) -{ - *ret = obj->val; - return TRUE; -} - -gboolean -my_object_get_value (MyObject *obj, guint *ret, GError **error) -{ - *ret = obj->val; - return TRUE; -} - -gboolean -my_object_echo_variant (MyObject *obj, GValue *variant, GValue *ret, GError **error) -{ - GType t; - t = G_VALUE_TYPE(variant); - g_value_init (ret, t); - g_value_copy (variant, ret); - - return TRUE; -} - -gboolean -my_object_process_variant_of_array_of_ints123 (MyObject *obj, GValue *variant, GError **error) -{ - GArray *array; - int i; - int j; - - j = 0; - - array = (GArray *)g_value_get_boxed (variant); - - for (i = 0; i <= 2; i++) - { - j = g_array_index (array, int, i); - if (j != i + 1) - goto error; - } - - return TRUE; - -error: - *error = g_error_new (MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "Error decoding a variant of type ai (i + 1 = %i, j = %i)", - i, j + 1); - return FALSE; -} - - -typedef struct _HashAndString HashAndString; - -struct _HashAndString -{ - GHashTable *hash; - gchar* string; -}; - -static void -hash_foreach_prepend_string (gpointer key, gpointer val, gpointer user_data) -{ - HashAndString *data = (HashAndString*) user_data; - gchar *in = (gchar*) val; - g_hash_table_insert (data->hash, g_strdup ((gchar*) key), - g_strjoin (" ", data->string, in, NULL)); -} - - -static void -hash_foreach_mangle_dict_of_strings (gpointer key, gpointer val, gpointer user_data) -{ - GHashTable *out = (GHashTable*) user_data; - GHashTable *in_dict = (GHashTable *) val; - HashAndString *data = g_new0 (HashAndString, 1); - - data->string = (gchar*) key; - data->hash = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - g_hash_table_foreach (in_dict, hash_foreach_prepend_string, data); - - g_hash_table_insert(out, g_strdup ((gchar*) key), data->hash); -} - -gboolean -my_object_dict_of_dicts (MyObject *obj, GHashTable *in, - GHashTable **out, GError **error) -{ - *out = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_hash_table_destroy); - g_hash_table_foreach (in, hash_foreach_mangle_dict_of_strings, *out); - return TRUE; -} - -gboolean -my_object_emit_frobnicate (MyObject *obj, GError **error) -{ - g_signal_emit (obj, signals[FROBNICATE], 0, 42); - return TRUE; -} - -gboolean -my_object_emit_signals (MyObject *obj, GError **error) -{ - GValue val = {0, }; - - g_signal_emit (obj, signals[SIG0], 0, "foo", 22, "moo"); - - g_value_init (&val, G_TYPE_STRING); - g_value_set_string (&val, "bar"); - g_signal_emit (obj, signals[SIG1], 0, "baz", &val); - g_value_unset (&val); - - return TRUE; -} - -gboolean -my_object_emit_signal2 (MyObject *obj, GError **error) -{ - GHashTable *table; - - table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (table, "baz", "cow"); - g_hash_table_insert (table, "bar", "foo"); - g_signal_emit (obj, signals[SIG2], 0, table); - g_hash_table_destroy (table); - return TRUE; -} - -typedef struct { - gint32 x; - DBusGMethodInvocation *context; -} IncrementData; - -static gboolean -do_async_increment (IncrementData *data) -{ - gint32 newx = data->x + 1; - dbus_g_method_return (data->context, newx); - g_free (data); - return FALSE; -} - -void -my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *context) -{ - IncrementData *data = g_new0 (IncrementData, 1); - data->x = x; - data->context = context; - g_idle_add ((GSourceFunc)do_async_increment, data); -} - -static gboolean -do_async_error (IncrementData *data) -{ - GError *error; - error = g_error_new (MY_OBJECT_ERROR, - MY_OBJECT_ERROR_FOO, - "%s", - "this method always loses"); - dbus_g_method_return_error (data->context, error); - g_free (data); - return FALSE; -} - -void -my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context) -{ - IncrementData *data = g_new0(IncrementData, 1); - data->context = context; - g_idle_add ((GSourceFunc)do_async_error, data); -} - - -static GMainLoop *loop; - -gboolean -my_object_terminate (MyObject *obj, GError **error) -{ - g_main_loop_quit (loop); - return TRUE; -} +GMainLoop *loop; #define TEST_SERVICE_NAME "org.freedesktop.DBus.GLib.TestService" @@ -855,9 +30,6 @@ main (int argc, char **argv) g_type_init (); g_thread_init (NULL); dbus_g_thread_init (); - dbus_g_object_type_install_info (MY_TYPE_OBJECT, - &dbus_glib_my_object_object_info); - dbus_g_error_domain_register (MY_OBJECT_ERROR, NULL, MY_TYPE_ERROR); diff --git a/test/core/test-service-glib.xml b/test/core/test-service-glib.xml index fca02af..be262d6 100644 --- a/test/core/test-service-glib.xml +++ b/test/core/test-service-glib.xml @@ -2,6 +2,10 @@ <node name="/org/freedesktop/DBus/GLib/Tests/MyTestObject"> <interface name="org.freedesktop.DBus.GLib.Tests.MyObject"> + <property name="this_is_a_string" type="s" access="readwrite"/> + <property name="no-touching" type="u" access="read"/> + <property name="SuperStudly" type="d" access="readwrite"/> + <method name="DoNothing"> </method> @@ -145,6 +149,9 @@ <method name="EmitFrobnicate"> </method> + <method name="UnsafeDisableLegacyPropertyAccess"> + </method> + <!-- Export signals --> <signal name="Frobnicate"/> |