+ klass = g_type_class_ref (info->code_enum);
+ value = g_enum_get_value (klass, code);
+ g_type_class_unref (klass);
+
+ domain_str = info->default_iface;
+ code_str = value->value_nick;
+ }
+ }
+
+ if (!domain_str)
+ domain_str = msg_interface;
+
+ if (!domain_str || !code_str)
+ {
+ /* If we can't map it sensibly, make up an error name */
+ char *domain_from_quark;
+
+ dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
+
+ domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
+ g_string_append (dbus_error_name, domain_from_quark);
+ g_free (domain_from_quark);
+
+ g_string_append_printf (dbus_error_name, ".Code%d", code);
+ }
+ else
+ {
+ dbus_error_name = g_string_new (domain_str);
+ g_string_append_c (dbus_error_name, '.');
+ g_string_append (dbus_error_name, code_str);
+ }
+
+ return g_string_free (dbus_error_name, FALSE);
+}
+
+static DBusMessage *
+gerror_to_dbus_error_message (const DBusGObjectInfo *object_info,
+ DBusMessage *message,
+ GError *error)
+{
+ DBusMessage *reply;
+
+ if (!error)
+ {
+ char *error_msg;
+
+ error_msg = g_strdup_printf ("Method invoked for %s returned FALSE but did not set error", dbus_message_get_member (message));
+ reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error_msg);
+ g_free (error_msg);
+ }
+ else
+ {
+ if (error->domain == DBUS_GERROR)
+ reply = dbus_message_new_error (message,
+ dbus_g_error_get_name (error),
+ error->message);
+ else
+ {
+ char *error_name;
+ error_name = gerror_domaincode_to_dbus_error_name (object_info,
+ dbus_message_get_interface (message),
+ error->domain, error->code);
+ reply = dbus_message_new_error (message, error_name, error->message);
+ g_free (error_name);
+ }
+ }
+ return reply;
+}
+
+/**
+ * The context of an asynchronous method call. See dbus_g_method_return() and
+ * dbus_g_method_return_error().
+ */
+struct _DBusGMethodInvocation {
+ DBusGConnection *connection; /**< The connection */
+ DBusGMessage *message; /**< The message which generated the method call */
+ const DBusGObjectInfo *object; /**< The object the method was called on */
+ const DBusGMethodInfo *method; /**< The method called */
+};
+
+static DBusHandlerResult
+invoke_object_method (GObject *object,
+ const DBusGObjectInfo *object_info,
+ const DBusGMethodInfo *method,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ gboolean had_error, call_only;
+ GError *gerror;
+ GValueArray *value_array;
+ GValue return_value = {0,};
+ GClosure closure;
+ char *in_signature;
+ GArray *out_param_values = NULL;
+ GValueArray *out_param_gvalues = NULL;
+ int out_param_count;
+ int out_param_pos, out_param_gvalue_pos;
+ DBusHandlerResult result;
+ DBusMessage *reply;
+ gboolean have_retval;
+ gboolean retval_signals_error;
+ gboolean retval_is_synthetic;
+ gboolean retval_is_constant;
+ const char *arg_metadata;
+
+ gerror = NULL;
+
+ /* Determine whether or not this method should be invoked in a new
+ thread
+ */
+ if (strcmp (string_table_lookup (get_method_data (object_info, method), 2), "A") == 0)
+ call_only = TRUE;
+ else
+ call_only = FALSE;
+
+ have_retval = FALSE;
+ retval_signals_error = FALSE;
+ retval_is_synthetic = FALSE;
+ retval_is_constant = FALSE;
+
+ /* This is evil. We do this to work around the fact that
+ * the generated glib marshallers check a flag in the closure object
+ * which we don't care about. We don't need/want to create
+ * a new closure for each invocation.
+ */
+ memset (&closure, 0, sizeof (closure));
+
+ in_signature = method_input_signature_from_object_info (object_info, method);
+
+ /* Convert method IN parameters to GValueArray */
+ {
+ GArray *types_array;
+ guint n_params;
+ const GType *types;
+ DBusGValueMarshalCtx context;
+ GError *error = NULL;
+
+ context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (connection);
+ context.proxy = NULL;
+
+ types_array = _dbus_gtypes_from_arg_signature (in_signature, FALSE);
+ n_params = types_array->len;
+ types = (const GType*) types_array->data;
+
+ value_array = _dbus_gvalue_demarshal_message (&context, message, n_params, types, &error);
+ if (value_array == NULL)
+ {
+ g_free (in_signature);
+ g_array_free (types_array, TRUE);
+ reply = dbus_message_new_error (message, "org.freedesktop.DBus.GLib.ErrorError", error->message);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ g_error_free (error);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ g_array_free (types_array, TRUE);
+ }
+
+ /* Prepend object as first argument */
+ g_value_array_prepend (value_array, NULL);
+ g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_OBJECT);
+ g_value_set_object (g_value_array_get_nth (value_array, 0), object);
+
+ if (call_only)
+ {
+ GValue context_value = {0,};
+ DBusGMethodInvocation *context;
+ context = g_new (DBusGMethodInvocation, 1);
+ context->connection = dbus_g_connection_ref (DBUS_G_CONNECTION_FROM_CONNECTION (connection));
+ context->message = dbus_g_message_ref (DBUS_G_MESSAGE_FROM_MESSAGE (message));
+ context->object = object_info;
+ context->method = method;
+ g_value_init (&context_value, G_TYPE_POINTER);
+ g_value_set_pointer (&context_value, context);
+ g_value_array_append (value_array, &context_value);
+ }
+ else
+ {
+ RetvalType retval;
+ gboolean arg_in;
+ gboolean arg_const;
+ const char *argsig;
+
+ arg_metadata = method_arg_info_from_object_info (object_info, method);
+
+ /* Count number of output parameters, and look for a return value */
+ out_param_count = 0;
+ while (*arg_metadata)
+ {
+ arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, &arg_const, &retval, &argsig);
+ if (arg_in)
+ continue;
+ if (retval != RETVAL_NONE)
+ {
+ DBusSignatureIter tmp_sigiter;
+ /* This is the function return value */
+ g_assert (!have_retval);
+ have_retval = TRUE;
+ retval_is_synthetic = FALSE;
+
+ switch (retval)
+ {
+ case RETVAL_NONE:
+ g_assert_not_reached ();
+ break;
+ case RETVAL_NOERROR:
+ retval_signals_error = FALSE;
+ break;
+ case RETVAL_ERROR:
+ retval_signals_error = TRUE;
+ break;
+ }
+
+ retval_is_constant = arg_const;
+
+ /* Initialize our return GValue with the specified type */
+ dbus_signature_iter_init (&tmp_sigiter, argsig);
+ g_value_init (&return_value, _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE));
+ }
+ else
+ {
+ /* It's a regular output value */
+ out_param_count++;
+ }
+ }
+
+ /* For compatibility, if we haven't found a return value, we assume
+ * the function returns a gboolean for signalling an error
+ * (and therefore also takes a GError). We also note that it
+ * is a "synthetic" return value; i.e. we aren't going to be
+ * sending it over the bus, it's just to signal an error.
+ */
+ if (!have_retval)
+ {
+ have_retval = TRUE;
+ retval_is_synthetic = TRUE;
+ retval_signals_error = TRUE;
+ g_value_init (&return_value, G_TYPE_BOOLEAN);
+ }
+
+ /* Create an array to store the actual values of OUT parameters
+ * (other than the real function return, if any). Then, create
+ * a GValue boxed POINTER to each of those values, and append to
+ * the invocation, so the method can return the OUT parameters.
+ */
+ out_param_values = g_array_sized_new (FALSE, TRUE, sizeof (GTypeCValue), out_param_count);
+
+ /* We have a special array of GValues for toplevel GValue return
+ * types.
+ */
+ out_param_gvalues = g_value_array_new (out_param_count);
+ out_param_pos = 0;
+ out_param_gvalue_pos = 0;
+
+ /* Reset argument metadata pointer */
+ arg_metadata = method_arg_info_from_object_info (object_info, method);
+
+ /* Iterate over output arguments again, this time allocating space for
+ * them as appopriate.
+ */
+ while (*arg_metadata)
+ {
+ GValue value = {0, };
+ GTypeCValue storage;
+ DBusSignatureIter tmp_sigiter;
+ GType current_gtype;
+
+ arg_metadata = arg_iterate (arg_metadata, NULL, &arg_in, NULL, &retval, &argsig);
+ /* Skip over input arguments and the return value, if any */
+ if (arg_in || retval != RETVAL_NONE)
+ continue;
+
+ dbus_signature_iter_init (&tmp_sigiter, argsig);
+ current_gtype = _dbus_gtype_from_signature_iter (&tmp_sigiter, FALSE);
+
+ g_value_init (&value, G_TYPE_POINTER);
+
+ /* We special case variants to make method invocation a bit nicer */
+ if (current_gtype != G_TYPE_VALUE)
+ {
+ memset (&storage, 0, sizeof (storage));
+ g_array_append_val (out_param_values, storage);
+ g_value_set_pointer (&value, &(g_array_index (out_param_values, GTypeCValue, out_param_pos)));
+ out_param_pos++;
+ }
+ else
+ {
+ g_value_array_append (out_param_gvalues, NULL);
+ g_value_set_pointer (&value, out_param_gvalues->values + out_param_gvalue_pos);
+ out_param_gvalue_pos++;
+ }
+ g_value_array_append (value_array, &value);
+ }
+ }
+
+ /* Append GError as final argument if necessary */
+ if (retval_signals_error)
+ {
+ g_assert (have_retval);
+ g_value_array_append (value_array, NULL);
+ g_value_init (g_value_array_get_nth (value_array, value_array->n_values - 1), G_TYPE_POINTER);
+ g_value_set_pointer (g_value_array_get_nth (value_array, value_array->n_values - 1), &gerror);
+ }
+
+ /* Actually invoke method */
+ method->marshaller (&closure, have_retval ? &return_value : NULL,
+ value_array->n_values,
+ value_array->values,
+ NULL, method->function);
+ if (call_only)
+ {
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ goto done;
+ }
+ if (retval_signals_error)
+ had_error = _dbus_gvalue_signals_error (&return_value);
+ else
+ had_error = FALSE;
+
+ if (!had_error)
+ {
+ DBusMessageIter iter;
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ goto nomem;
+
+ /* Append output arguments to reply */
+ dbus_message_iter_init_append (reply, &iter);
+
+ /* First, append the return value, unless it's synthetic */
+ if (have_retval && !retval_is_synthetic)
+ {
+ if (!_dbus_gvalue_marshal (&iter, &return_value))
+ goto nomem;
+ if (!retval_is_constant)
+ g_value_unset (&return_value);
+ }
+
+ /* Grab the argument metadata and iterate over it */
+ arg_metadata = method_arg_info_from_object_info (object_info, method);
+
+ /* Now append any remaining return values */
+ out_param_pos = 0;
+ out_param_gvalue_pos = 0;
+ while (*arg_metadata)
+ {
+ GValue gvalue = {0, };
+ const char *arg_name;
+ gboolean arg_in;
+ gboolean constval;
+ RetvalType retval;
+ const char *arg_signature;
+ DBusSignatureIter argsigiter;
+
+ do
+ {
+ /* Iterate over only output values; skip over input
+ arguments and the return value */
+ arg_metadata = arg_iterate (arg_metadata, &arg_name, &arg_in, &constval, &retval, &arg_signature);
+ }
+ while ((arg_in || retval != RETVAL_NONE) && *arg_metadata);
+
+ /* If the last argument we saw was input or the return
+ * value, we must be done iterating over output arguments.
+ */
+ if (arg_in || retval != RETVAL_NONE)
+ break;
+
+ dbus_signature_iter_init (&argsigiter, arg_signature);
+
+ g_value_init (&gvalue, _dbus_gtype_from_signature_iter (&argsigiter, FALSE));
+ if (G_VALUE_TYPE (&gvalue) != G_TYPE_VALUE)
+ {
+ if (!_dbus_gvalue_take (&gvalue,
+ &(g_array_index (out_param_values, GTypeCValue, out_param_pos))))
+ g_assert_not_reached ();
+ out_param_pos++;
+ }
+ else
+ {
+ g_value_set_static_boxed (&gvalue, out_param_gvalues->values + out_param_gvalue_pos);
+ out_param_gvalue_pos++;
+ }
+
+ if (!_dbus_gvalue_marshal (&iter, &gvalue))
+ goto nomem;
+ /* Here we actually free the allocated value; we
+ * took ownership of it with _dbus_gvalue_take, unless
+ * an annotation has specified this value as constant.
+ */
+ if (!constval)
+ g_value_unset (&gvalue);
+ }
+ }
+ else
+ reply = gerror_to_dbus_error_message (object_info, message, gerror);
+
+ if (reply)
+ {
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ }
+
+ result = DBUS_HANDLER_RESULT_HANDLED;
+ done:
+ g_free (in_signature);
+ if (!call_only)
+ {
+ g_array_free (out_param_values, TRUE);
+ g_value_array_free (out_param_gvalues);
+ }
+ g_value_array_free (value_array);
+ return result;
+ nomem:
+ result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ goto done;
+}
+
+static DBusHandlerResult
+gobject_message_function (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GParamSpec *pspec;
+ GObject *object;
+ gboolean setter;
+ gboolean getter;
+ char *s;
+ const char *wincaps_propname;
+ /* const char *wincaps_propiface; */
+ DBusMessageIter iter;
+ const DBusGMethodInfo *method;
+ const DBusGObjectInfo *object_info;
+
+ object = G_OBJECT (user_data);
+
+ if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_INTROSPECTABLE,
+ "Introspect"))
+ return handle_introspect (connection, message, object);
+
+ /* Try the metainfo, which lets us invoke methods */
+ if (lookup_object_and_method (object, message, &object_info, &method))
+ return invoke_object_method (object, object_info, method, connection, message);
+
+ /* If no metainfo, we can still do properties and signals
+ * via standard GLib introspection
+ */
+ getter = FALSE;
+ setter = FALSE;
+ if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_PROPERTIES,
+ "Get"))
+ getter = TRUE;
+ else if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_PROPERTIES,
+ "Set"))
+ setter = TRUE;
+
+ if (!(setter || getter))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ dbus_message_iter_init (message, &iter);
+
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ {
+ 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_next (&iter);
+
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ {
+ 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_next (&iter);
+
+ s = _dbus_gutils_wincaps_to_uscore (wincaps_propname);