static int
test_load (const char *uri)
{
	RBMetaData *md;
	GError *error = NULL;
	int rv = 0;
	char **missing_plugins;
	char **plugin_descriptions;

	md = rb_metadata_new ();
	rb_metadata_load (md, uri, &error);
	if (error) {
		g_print ("Error loading metadata from %s: %s\n", uri, error->message);
		g_clear_error (&error);
		g_print ("media type: %s\n", rb_metadata_get_media_type (md));
		rv = -1;
	} else {
		int i;
		g_print ("media type: %s\n", rb_metadata_get_media_type (md));
		for (i=0; i<RB_METADATA_FIELD_LAST; i++) {
			GValue v = {0,};
			GValue sv = {0,};
			if (rb_metadata_get (md, i, &v)) {
				g_value_init (&sv, G_TYPE_STRING);
				g_value_transform (&v, &sv);

				g_print ("%s: %s\n", rb_metadata_get_field_name (i), g_value_get_string (&sv));

				g_value_unset (&v);
				g_value_unset (&sv);
			}
		}
	}

	g_print ("has audio: %d\n", rb_metadata_has_audio (md));
	g_print ("has video: %d\n", rb_metadata_has_video (md));
	g_print ("has other: %d\n", rb_metadata_has_other_data (md));

	if (rb_metadata_get_missing_plugins (md, &missing_plugins, &plugin_descriptions)) {
		int i = 0;
		g_print ("missing plugins:\n");
		while (missing_plugins[i] != NULL) {
			g_print ("\t%s (%s)\n", missing_plugins[i], plugin_descriptions[i]);
			i++;
		}
		g_strfreev (missing_plugins);
	}

	g_object_unref (G_OBJECT (md));
	return rv;
}
static void
rb_metadata_dbus_load (GVariant *parameters,
		       GDBusMethodInvocation *invocation,
		       ServiceData *svc)
{
	const char *uri;
	GError *error = NULL;
	GVariant *response;
	const char *nothing[] = { NULL };
	char **missing_plugins = NULL;
	char **plugin_descriptions = NULL;
	const char *mediatype;

	g_variant_get (parameters, "(&s)", &uri);

	rb_debug ("loading metadata from %s", uri);
	rb_metadata_load (svc->metadata, uri, &error);
	mediatype = rb_metadata_get_media_type (svc->metadata);
	rb_debug ("metadata load finished (type %s)", mediatype);

	rb_metadata_get_missing_plugins (svc->metadata, &missing_plugins, &plugin_descriptions);

	response = g_variant_new ("(^as^asbbbsbisa{iv})",
				  missing_plugins ? missing_plugins : (char **)nothing,
				  plugin_descriptions ? plugin_descriptions : (char **)nothing,
				  rb_metadata_has_audio (svc->metadata),
				  rb_metadata_has_video (svc->metadata),
				  rb_metadata_has_other_data (svc->metadata),
				  mediatype ? mediatype : "",
				  (error == NULL),
				  (error != NULL ? error->code : 0),
				  (error != NULL ? error->message : ""),
				  rb_metadata_dbus_get_variant_builder (svc->metadata));
	g_strfreev (missing_plugins);
	g_strfreev (plugin_descriptions);

	g_dbus_method_invocation_return_value (invocation, response);
}
static DBusHandlerResult
rb_metadata_dbus_load (DBusConnection *connection,
		       DBusMessage *message,
		       ServiceData *svc)
{
	char *uri;
	DBusMessageIter iter;
	DBusMessage *reply;
	GError *error = NULL;
	gboolean ok;
	const char *mimetype = NULL;
	char **missing_plugins = NULL;
	char **plugin_descriptions = NULL;
	gboolean has_audio;
	gboolean has_video;
	gboolean has_other_data;

	if (!dbus_message_iter_init (message, &iter)) {
		return DBUS_HANDLER_RESULT_NEED_MEMORY;
	}

	if (!rb_metadata_dbus_get_string (&iter, &uri)) {
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}

	rb_debug ("loading metadata from %s", uri);
	rb_metadata_load (svc->metadata, uri, &error);
	rb_debug ("metadata load finished (type %s)", rb_metadata_get_mime (svc->metadata));
	g_free (uri);

	/* construct reply */
	reply = dbus_message_new_method_return (message);
	if (!reply) {
		rb_debug ("out of memory creating return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}
	
	dbus_message_iter_init_append (reply, &iter);

	rb_metadata_get_missing_plugins (svc->metadata, &missing_plugins, &plugin_descriptions);
	if (!rb_metadata_dbus_add_strv (&iter, missing_plugins)) {
		rb_debug ("out of memory adding data to return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}
	if (!rb_metadata_dbus_add_strv (&iter, plugin_descriptions)) {
		rb_debug ("out of memory adding data to return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}

	mimetype = rb_metadata_get_mime (svc->metadata);
	if (mimetype == NULL) {
		mimetype = "";
	}
	has_audio = rb_metadata_has_audio (svc->metadata);
	has_video = rb_metadata_has_video (svc->metadata);
	has_other_data = rb_metadata_has_other_data (svc->metadata);

	if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &has_audio) ||
	    !dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &has_video) ||
	    !dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &has_other_data) ||
	    !dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &mimetype)) {
		rb_debug ("out of memory adding data to return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}

	ok = (error == NULL);
	if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &ok)) {
		rb_debug ("out of memory adding error flag to return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}

	if (error != NULL) {
		rb_debug ("metadata error: %s", error->message);
		if (append_error (&iter, error->code, error->message) == FALSE) {
			rb_debug ("out of memory adding error details to return message");
			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
		}
	}

	if (!rb_metadata_dbus_add_to_message (svc->metadata, &iter)) {
		rb_debug ("unable to add metadata to return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}

	if (!dbus_connection_send (connection, reply, NULL)) {
		rb_debug ("failed to send return message");
		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
	}

	dbus_message_unref (reply);
	return DBUS_HANDLER_RESULT_HANDLED;
}