/*
* dLeyna
*
* Copyright (C) 2012-2017 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Mark Ryan <mark.d.ryan@intel.com>
*
*/
#include <libdleyna/core/error.h>
#include <libdleyna/core/log.h>
#include "async.h"
#include "path.h"
static void prv_delete(dls_task_t *task)
{
if (!task->synchronous)
dls_async_task_delete((dls_async_task_t *)task);
switch (task->type) {
case DLS_TASK_GET_CHILDREN:
if (task->ut.get_children.filter)
g_variant_unref(task->ut.get_children.filter);
g_free(task->ut.get_children.sort_by);
break;
case DLS_TASK_MANAGER_GET_ALL_PROPS:
case DLS_TASK_GET_ALL_PROPS:
g_free(task->ut.get_props.interface_name);
break;
case DLS_TASK_MANAGER_GET_PROP:
case DLS_TASK_GET_PROP:
g_free(task->ut.get_prop.interface_name);
g_free(task->ut.get_prop.prop_name);
break;
case DLS_TASK_MANAGER_SET_PROP:
g_free(task->ut.set_prop.interface_name);
g_free(task->ut.set_prop.prop_name);
g_variant_unref(task->ut.set_prop.params);
break;
case DLS_TASK_SEARCH:
g_free(task->ut.search.query);
if (task->ut.search.filter)
g_variant_unref(task->ut.search.filter);
g_free(task->ut.search.sort_by);
break;
case DLS_TASK_BROWSE_OBJECTS:
if (task->ut.browse_objects.objects)
g_variant_unref(task->ut.browse_objects.objects);
if (task->ut.browse_objects.filter)
g_variant_unref(task->ut.browse_objects.filter);
break;
case DLS_TASK_GET_RESOURCE:
if (task->ut.resource.filter)
g_variant_unref(task->ut.resource.filter);
g_free(task->ut.resource.protocol_info);
break;
case DLS_TASK_SET_PROTOCOL_INFO:
if (task->ut.protocol_info.protocol_info)
g_free(task->ut.protocol_info.protocol_info);
break;
case DLS_TASK_UPLOAD_TO_ANY:
case DLS_TASK_UPLOAD:
g_free(task->ut.upload.display_name);
g_free(task->ut.upload.file_path);
break;
case DLS_TASK_CREATE_CONTAINER:
case DLS_TASK_CREATE_CONTAINER_IN_ANY:
g_free(task->ut.create_container.display_name);
g_free(task->ut.create_container.type);
if (task->ut.create_container.child_types)
g_variant_unref(task->ut.create_container.child_types);
break;
case DLS_TASK_UPDATE_OBJECT:
if (task->ut.update.to_add_update)
g_variant_unref(task->ut.update.to_add_update);
if (task->ut.update.to_delete)
g_variant_unref(task->ut.update.to_delete);
break;
case DLS_TASK_CREATE_REFERENCE:
g_free(task->ut.create_reference.item_path);
break;
case DLS_TASK_GET_ICON:
g_free(task->ut.get_icon.resolution);
g_free(task->ut.get_icon.mime_type);
break;
case DLS_TASK_WAKE:
break;
default:
break;
}
g_free(task->target.path);
g_free(task->target.root_path);
g_free(task->target.id);
if (task->result)
g_variant_unref(task->result);
g_free(task);
}
dls_task_t *dls_task_rescan_new(dleyna_connector_msg_id_t invocation)
{
dls_task_t *task = g_new0(dls_task_t, 1);
task->type = DLS_TASK_RESCAN;
task->invocation = invocation;
task->synchronous = TRUE;
return task;
}
dls_task_t *dls_task_get_version_new(dleyna_connector_msg_id_t invocation)
{
dls_task_t *task = g_new0(dls_task_t, 1);
task->type = DLS_TASK_GET_VERSION;
task->invocation = invocation;
task->result_format = "(@s)";
task->synchronous = TRUE;
return task;
}
dls_task_t *dls_task_get_servers_new(dleyna_connector_msg_id_t invocation)
{
dls_task_t *task = g_new0(dls_task_t, 1);
task->type = DLS_TASK_GET_SERVERS;
task->invocation = invocation;
task->result_format = "(@ao)";
task->synchronous = TRUE;
return task;
}
dls_task_t *dls_task_manager_get_prop_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1);
g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name,
&task->ut.get_prop.prop_name);
g_strstrip(task->ut.get_prop.interface_name);
g_strstrip(task->ut.get_prop.prop_name);
task->target.path = g_strstrip(g_strdup(path));
task->type = DLS_TASK_MANAGER_GET_PROP;
task->invocation = invocation;
task->result_format = "(v)";
return task;
}
dls_task_t *dls_task_manager_get_props_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1);
g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name);
g_strstrip(task->ut.get_props.interface_name);
task->target.path = g_strstrip(g_strdup(path));
task->type = DLS_TASK_MANAGER_GET_ALL_PROPS;
task->invocation = invocation;
task->result_format = "(@a{sv})";
return task;
}
dls_task_t *dls_task_manager_set_prop_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1);
g_variant_get(parameters, "(ssv)",
&task->ut.set_prop.interface_name,
&task->ut.set_prop.prop_name,
&task->ut.set_prop.params);
g_strstrip(task->ut.set_prop.interface_name);
g_strstrip(task->ut.set_prop.prop_name);
task->target.path = g_strstrip(g_strdup(path));
task->type = DLS_TASK_MANAGER_SET_PROP;
task->invocation = invocation;
return task;
}
static gboolean prv_set_task_target_info(dls_task_t *task, const gchar *path,
GError **error)
{
task->target.path = g_strdup(path);
g_strstrip(task->target.path);
return dls_server_get_object_info(path, &task->target.root_path,
&task->target.id,
&task->target.device, error);
}
static gboolean prv_is_task_allowed(dls_task_t *task, GError **error)
{
if (dls_server_is_device_sleeping(task->target.device)) {
if (task->type != DLS_TASK_WAKE &&
task->type != DLS_TASK_GET_PROP)
goto on_error;
}
return TRUE;
on_error:
*error = g_error_new(DLEYNA_SERVER_ERROR,
DLEYNA_ERROR_OPERATION_FAILED,
"Target device is sleeping");
return FALSE;
}
static dls_task_t *prv_m2spec_task_new(dls_task_type_t type,
dleyna_connector_msg_id_t invocation,
const gchar *path,
const gchar *result_format,
GError **error,
gboolean synchronous)
{
dls_task_t *task;
if (synchronous) {
task = g_new0(dls_task_t, 1);
task->synchronous = TRUE;
} else {
task = (dls_task_t *)g_new0(dls_async_task_t, 1);
}
task->type = type;
if (!prv_set_task_target_info(task, path, error) ||
!prv_is_task_allowed(task, error)) {
prv_delete(task);
task = NULL;
goto finished;
}
task->invocation = invocation;
task->result_format = result_format;
finished:
return task;
}
dls_task_t *dls_task_get_children_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
gboolean items, gboolean containers,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_CHILDREN, invocation, path,
"(@aa{sv})", error, FALSE);
if (!task)
goto finished;
task->ut.get_children.containers = containers;
task->ut.get_children.items = items;
g_variant_get(parameters, "(uu@as)",
&task->ut.get_children.start,
&task->ut.get_children.count,
&task->ut.get_children.filter);
task->ut.get_children.sort_by = g_strdup("");
finished:
return task;
}
dls_task_t *dls_task_get_children_ex_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters, gboolean items,
gboolean containers,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_CHILDREN, invocation, path,
"(@aa{sv})", error, FALSE);
if (!task)
goto finished;
task->ut.get_children.containers = containers;
task->ut.get_children.items = items;
g_variant_get(parameters, "(uu@ass)",
&task->ut.get_children.start,
&task->ut.get_children.count,
&task->ut.get_children.filter,
&task->ut.get_children.sort_by);
finished:
return task;
}
dls_task_t *dls_task_get_prop_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_PROP, invocation, path, "(v)",
error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name,
&task->ut.get_prop.prop_name);
g_strstrip(task->ut.get_prop.interface_name);
g_strstrip(task->ut.get_prop.prop_name);
finished:
return task;
}
dls_task_t *dls_task_get_props_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_ALL_PROPS, invocation, path,
"(@a{sv})", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name);
g_strstrip(task->ut.get_props.interface_name);
finished:
return task;
}
dls_task_t *dls_task_search_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_SEARCH, invocation, path,
"(@aa{sv})", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(suu@as)", &task->ut.search.query,
&task->ut.search.start, &task->ut.search.count,
&task->ut.search.filter);
task->ut.search.sort_by = g_strdup("");
finished:
return task;
}
dls_task_t *dls_task_search_ex_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_SEARCH, invocation, path,
"(@aa{sv}u)", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(suu@ass)", &task->ut.search.query,
&task->ut.search.start, &task->ut.search.count,
&task->ut.search.filter, &task->ut.search.sort_by);
task->multiple_retvals = TRUE;
finished:
return task;
}
dls_task_t *dls_task_browse_objects_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_BROWSE_OBJECTS, invocation, path,
"(@aa{sv})", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(@ao@as)",
&task->ut.browse_objects.objects,
&task->ut.browse_objects.filter);
finished:
return task;
}
dls_task_t *dls_task_get_resource_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_RESOURCE, invocation, path,
"(@a{sv})", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(s@as)",
&task->ut.resource.protocol_info,
&task->ut.resource.filter);
finished:
return task;
}
dls_task_t *dls_task_set_protocol_info_new(dleyna_connector_msg_id_t invocation,
GVariant *parameters)
{
dls_task_t *task = g_new0(dls_task_t, 1);
task->type = DLS_TASK_SET_PROTOCOL_INFO;
task->invocation = invocation;
task->synchronous = TRUE;
g_variant_get(parameters, "(s)", &task->ut.protocol_info.protocol_info);
return task;
}
static dls_task_t *prv_upload_new_generic(dls_task_type_t type,
dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(type, invocation, path,
"(uo)", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(ss)", &task->ut.upload.display_name,
&task->ut.upload.file_path);
g_strstrip(task->ut.upload.file_path);
task->multiple_retvals = TRUE;
finished:
return task;
}
dls_task_t *dls_task_prefer_local_addresses_new(
dleyna_connector_msg_id_t invocation,
GVariant *parameters)
{
dls_task_t *task = g_new0(dls_task_t, 1);
task->type = DLS_TASK_SET_PREFER_LOCAL_ADDRESSES;
task->invocation = invocation;
task->synchronous = TRUE;
g_variant_get(parameters, "(b)",
&task->ut.prefer_local_addresses.prefer);
return task;
}
dls_task_t *dls_task_upload_to_any_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
return prv_upload_new_generic(DLS_TASK_UPLOAD_TO_ANY, invocation,
path, parameters, error);
}
dls_task_t *dls_task_upload_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
return prv_upload_new_generic(DLS_TASK_UPLOAD, invocation,
path, parameters, error);
}
dls_task_t *dls_task_get_upload_status_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_UPLOAD_STATUS, invocation, path,
"(stt)", error, TRUE);
if (!task)
goto finished;
g_variant_get(parameters, "(u)",
&task->ut.upload_action.upload_id);
task->multiple_retvals = TRUE;
finished:
return task;
}
dls_task_t *dls_task_get_upload_ids_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_UPLOAD_IDS, invocation, path,
"(@au)", error, TRUE);
return task;
}
dls_task_t *dls_task_cancel_upload_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_CANCEL_UPLOAD, invocation, path,
NULL, error, TRUE);
if (!task)
goto finished;
g_variant_get(parameters, "(u)",
&task->ut.upload_action.upload_id);
finished:
return task;
}
dls_task_t *dls_task_delete_new(dleyna_connector_msg_id_t invocation,
const gchar *path,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_DELETE_OBJECT, invocation,
path, NULL, error, FALSE);
return task;
}
dls_task_t *dls_task_create_container_new_generic(
dleyna_connector_msg_id_t invocation,
dls_task_type_t type,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(type, invocation, path,
"(@o)", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(ss@as)",
&task->ut.create_container.display_name,
&task->ut.create_container.type,
&task->ut.create_container.child_types);
finished:
return task;
}
dls_task_t *dls_task_create_reference_new(dleyna_connector_msg_id_t invocation,
dls_task_type_t type,
const gchar *path,
GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(type, invocation, path,
"(@o)", error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(o)", &task->ut.create_reference.item_path);
(void) g_strstrip(task->ut.create_reference.item_path);
finished:
return task;
}
dls_task_t *dls_task_update_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_UPDATE_OBJECT, invocation, path,
NULL, error, FALSE);
if (!task)
goto finished;
g_variant_get(parameters, "(@a{sv}@as)",
&task->ut.update.to_add_update,
&task->ut.update.to_delete);
finished:
return task;
}
dls_task_t *dls_task_get_metadata_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_OBJECT_METADATA, invocation,
path, "(@s)", error, FALSE);
return task;
}
dls_task_t *dls_task_get_icon_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GVariant *parameters,
GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_GET_ICON, invocation, path,
"(@ays)", error, FALSE);
if (!task)
goto finished;
task->multiple_retvals = TRUE;
g_variant_get(parameters, "(ss)", &task->ut.get_icon.mime_type,
&task->ut.get_icon.resolution);
finished:
return task;
}
dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation,
const gchar *path, GError **error)
{
dls_task_t *task;
task = prv_m2spec_task_new(DLS_TASK_WAKE, invocation, path,
NULL, error, FALSE);
return task;
}
void dls_task_complete(dls_task_t *task)
{
GVariant *variant = NULL;
if (!task)
goto finished;
if (task->invocation) {
if (task->result_format) {
if (task->multiple_retvals)
variant = g_variant_ref(task->result);
else
variant = g_variant_ref_sink(
g_variant_new(task->result_format,
task->result));
}
dls_server_get_connector()->return_response(task->invocation,
variant);
if (variant)
g_variant_unref(variant);
task->invocation = NULL;
}
finished:
return;
}
void dls_task_fail(dls_task_t *task, GError *error)
{
if (!task)
goto finished;
if (task->invocation) {
dls_server_get_connector()->return_error(task->invocation,
error);
task->invocation = NULL;
}
finished:
return;
}
void dls_task_cancel(dls_task_t *task)
{
GError *error;
if (!task)
goto finished;
if (task->invocation) {
error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_CANCELLED,
"Operation cancelled.");
dls_server_get_connector()->return_error(task->invocation,
error);
task->invocation = NULL;
g_error_free(error);
}
if (!task->synchronous)
dls_async_task_cancel((dls_async_task_t *)task);
finished:
return;
}
void dls_task_delete(dls_task_t *task)
{
GError *error;
if (!task)
goto finished;
if (task->invocation) {
error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_DIED,
"Unable to complete command.");
dls_server_get_connector()->return_error(task->invocation,
error);
g_error_free(error);
}
prv_delete(task);
finished:
return;
}