#include <string.h>
+#include <libgssdp/gssdp-resource-browser.h>
#include <libgupnp/gupnp-control-point.h>
#include <libgupnp/gupnp-error.h>
#include "async.h"
+#include "chain-task.h"
#include "device.h"
#include "error.h"
#include "interface.h"
GDBusConnection *connection;
msu_interface_info_t *interface_info;
GHashTable *filter_map;
+ GHashTable *property_map;
msu_upnp_callback_t found_server;
msu_upnp_callback_t lost_server;
GUPnPContextManager *context_manager;
void *user_data;
GHashTable *server_udn_map;
+ GHashTable *server_uc_map;
guint counter;
};
+/* Private structure used in chain task */
+typedef struct prv_device_new_ct_t_ prv_device_new_ct_t;
+struct prv_device_new_ct_t_ {
+ msu_upnp_t *upnp;
+ const char *udn;
+ msu_device_t *device;
+ msu_chain_task_t *chain;
+};
+
static gchar **prv_subtree_enumerate(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, interface_name))
retval = upnp->interface_info[
MSU_INTERFACE_INFO_CONTAINER].vtable;
+ else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, interface_name))
+ retval = upnp->interface_info[
+ MSU_INTERFACE_INFO_OBJECT].vtable;
else if (!strcmp(MSU_INTERFACE_PROPERTIES, interface_name))
retval = upnp->interface_info[
MSU_INTERFACE_INFO_PROPERTIES].vtable;
return retval;
}
+static void prv_device_chain_end(msu_chain_task_t *chain, gpointer data)
+{
+ msu_device_t *device;
+ gboolean canceled;
+ prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *) data;
+
+ device = msu_chain_task_get_device(chain);
+ canceled = msu_chain_task_is_canceled(chain);
+ if (canceled)
+ goto on_clear;
+
+ MSU_LOG_DEBUG("Notify new server available: %s", device->path);
+ g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
+ device);
+ priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
+
+on_clear:
+
+ g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
+ msu_chain_task_delete(chain);
+ g_free(priv_t);
+
+ if (canceled)
+ msu_device_delete(device);
+
+ MSU_LOG_DEBUG_NL();
+}
+
static void prv_server_available_cb(GUPnPControlPoint *cp,
GUPnPDeviceProxy *proxy,
gpointer user_data)
msu_device_t *device;
const gchar *ip_address;
msu_device_context_t *context;
+ msu_chain_task_t *chain;
unsigned int i;
-
- MSU_LOG_DEBUG("Enter");
+ prv_device_new_ct_t *priv_t;
udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
if (!udn)
device = g_hash_table_lookup(upnp->server_udn_map, udn);
if (!device) {
+ priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+
+ if (priv_t)
+ device = priv_t->device;
+ }
+
+ if (!device) {
MSU_LOG_DEBUG("Device not found. Adding");
+ MSU_LOG_DEBUG_NL();
- if (msu_device_new(upnp->connection, proxy,
- ip_address, &gSubtreeVtable, upnp,
- upnp->counter, &device)) {
- upnp->counter++;
- g_hash_table_insert(upnp->server_udn_map, g_strdup(udn),
- device);
- upnp->found_server(device->path, upnp->user_data);
- }
+ priv_t = g_new0(prv_device_new_ct_t, 1);
+ chain = msu_chain_task_new(prv_device_chain_end, priv_t);
+ device = msu_device_new(upnp->connection, proxy, ip_address,
+ &gSubtreeVtable, upnp,
+ upnp->property_map, upnp->counter,
+ chain);
+
+ upnp->counter++;
+
+ priv_t->upnp = upnp;
+ priv_t->udn = udn;
+ priv_t->chain = chain;
+ priv_t->device = device;
+
+ g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
} else {
MSU_LOG_DEBUG("Device Found");
msu_device_append_new_context(device, ip_address,
proxy);
}
+
+ MSU_LOG_DEBUG_NL();
}
on_error:
- MSU_LOG_DEBUG("Exit");
- MSU_LOG_DEBUG_NL();
-
return;
}
unsigned int i;
msu_device_context_t *context;
gboolean subscribed;
+ gboolean under_construction = FALSE;
+ prv_device_new_ct_t *priv_t;
MSU_LOG_DEBUG("Enter");
MSU_LOG_DEBUG("IP Address %s", ip_address);
device = g_hash_table_lookup(upnp->server_udn_map, udn);
+
+ if (!device) {
+ priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+
+ if (priv_t) {
+ device = priv_t->device;
+ under_construction = TRUE;
+ }
+ }
+
if (!device) {
MSU_LOG_WARNING("Device not found. Ignoring");
goto on_error;
(void) g_ptr_array_remove_index(device->contexts, i);
if (device->contexts->len == 0) {
- MSU_LOG_DEBUG("Last Context lost. Delete device");
- upnp->lost_server(device->path, upnp->user_data);
- g_hash_table_remove(upnp->server_udn_map, udn);
+ if (!under_construction) {
+ MSU_LOG_DEBUG("Last Context lost. " \
+ "Delete device");
+
+ upnp->lost_server(device->path,
+ upnp->user_data);
+ g_hash_table_remove(upnp->server_udn_map, udn);
+ } else {
+ MSU_LOG_WARNING("Device under construction. "\
+ "Cancelling");
+
+ msu_chain_task_cancel(priv_t->chain);
+ prv_device_chain_end(priv_t->chain, priv_t);
+ }
} else if (subscribed && !device->timeout_id) {
MSU_LOG_DEBUG("Subscribe on new context");
upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free,
msu_device_delete);
- upnp->filter_map = msu_prop_maps_new();
+
+ upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ msu_prop_maps_new(&upnp->property_map, &upnp->filter_map);
+
upnp->context_manager = gupnp_context_manager_create(0);
g_signal_connect(upnp->context_manager, "context-available",
{
if (upnp) {
g_object_unref(upnp->context_manager);
+ g_hash_table_unref(upnp->property_map);
g_hash_table_unref(upnp->filter_map);
g_hash_table_unref(upnp->server_udn_map);
+ g_hash_table_unref(upnp->server_uc_map);
g_free(upnp->interface_info);
g_free(upnp);
}
return retval;
}
-void msu_upnp_get_children(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_bas_t *cb_task_data;
MSU_LOG_DEBUG("Start: %u", task->ut.get_children.start);
MSU_LOG_DEBUG("Count: %u", task->ut.get_children.count);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.bas;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("Sort By %s", sort_by);
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
- msu_device_get_children(device, task, cb_data,
+ msu_device_get_children(device, client, task, cb_data,
upnp_filter, sort_by, cancellable);
on_error:
MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
}
-void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
gboolean root_object;
msu_async_cb_data_t *cb_data;
MSU_LOG_DEBUG("Path: %s", task->path);
MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.get_all;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
goto on_error;
}
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
- msu_device_get_all_props(device, task, cb_data, root_object,
+ msu_device_get_all_props(device, client, task, cb_data, root_object,
cancellable);
MSU_LOG_DEBUG("Exit with SUCCESS");
MSU_LOG_DEBUG("Exit with FAIL");
}
-void msu_upnp_get_prop(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
gboolean root_object;
msu_async_cb_data_t *cb_data;
MSU_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
task_data = &task->ut.get_prop;
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.get_prop;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
goto on_error;
}
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
- msu_device_get_prop(device, task, cb_data, prop_map,
+ msu_device_get_prop(device, client, task, cb_data, prop_map,
root_object, cancellable);
MSU_LOG_DEBUG("Exit with SUCCESS");
MSU_LOG_DEBUG("Exit with FAIL");
}
-void msu_upnp_search(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
gchar *upnp_filter = NULL;
gchar *upnp_query = NULL;
MSU_LOG_DEBUG("Start: %u", task->ut.search.start);
MSU_LOG_DEBUG("Count: %u", task->ut.search.count);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.bas;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("Sort By %s", sort_by);
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
- msu_device_search(device, task, cb_data, upnp_filter,
+ msu_device_search(device, client, task, cb_data, upnp_filter,
upnp_query, sort_by, cancellable);
on_error:
MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
}
-void msu_upnp_get_resource(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_get_all_t *cb_task_data;
MSU_LOG_DEBUG("Protocol Info: %s ", task->ut.resource.protocol_info);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.get_all;
if (!msu_path_get_path_and_id(task->path, &root_path, &cb_data->id,
MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
- msu_device_get_resource(device, task, cb_data, upnp_filter,
+ msu_device_get_resource(device, client, task, cb_data, upnp_filter,
cancellable);
on_error:
return FALSE;
}
-void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_upload_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.upload;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
- msu_device_upload(device, task, "DLNA.ORG_AnyContainer", cb_data,
- cancellable);
+ msu_device_upload(device, client, task, "DLNA.ORG_AnyContainer",
+ cb_data, cancellable);
on_error:
MSU_LOG_DEBUG("Exit");
}
-void msu_upnp_upload(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_upload(msu_upnp_t *upnp, msu_client_t *client, msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_upload_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.upload;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
- msu_device_upload(device, task, cb_data->id, cb_data, cancellable);
+ msu_device_upload(device, client, task, cb_data->id, cb_data,
+ cancellable);
+
+on_error:
+
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task)
+{
+ gchar *root_path = NULL;
+ gchar *id = NULL;
+ GError *error = NULL;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (strcmp(id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "GetUploadStatus must be executed "
+ " on a root path");
+ goto on_error;
+ }
+
+ (void) msu_device_get_upload_status(device, task, &error);
+
+on_error:
+
+ if (error) {
+ msu_task_fail_and_delete(task, error);
+ g_error_free(error);
+ } else {
+ msu_task_complete_and_delete(task);
+ }
+
+ g_free(id);
+ g_free(root_path);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task)
+{
+ gchar *root_path = NULL;
+ gchar *id = NULL;
+ GError *error = NULL;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (strcmp(id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "GetUploadIDs must be executed "
+ " on a root path");
+ goto on_error;
+ }
+
+ msu_device_get_upload_ids(device, task);
+
+on_error:
+
+ if (error) {
+ msu_task_fail_and_delete(task, error);
+ g_error_free(error);
+ } else {
+ msu_task_complete_and_delete(task);
+ }
+
+ g_free(id);
+ g_free(root_path);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task)
+{
+ gchar *root_path = NULL;
+ gchar *id = NULL;
+ GError *error = NULL;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (strcmp(id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "CancelUpload must be executed "
+ " on a root path");
+ goto on_error;
+ }
+
+ (void) msu_device_cancel_upload(device, task, &error);
+
+on_error:
+
+ if (error) {
+ msu_task_fail_and_delete(task, error);
+ g_error_free(error);
+ } else {
+ msu_task_complete_and_delete(task);
+ }
+
+ g_free(id);
+ g_free(root_path);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_device_t *device;
+ gchar *root_path = NULL;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+
+ if (!msu_path_get_path_and_id(task->path, &root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path,
+ cb_data->id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ msu_device_delete_object(device, client, task, cb_data, cancellable);
+
+on_error:
+
+ if (root_path)
+ g_free(root_path);
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_async_create_container_t *cb_task_data;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+ cb_task_data = &cb_data->ut.create_container;
+
+ if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
+ cb_data->id);
+
+ device = msu_device_from_path(cb_task_data->root_path,
+ upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ cb_task_data->root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ msu_device_create_container(device, client, task, cb_data->id,
+ cb_data, cancellable);
on_error:
MSU_LOG_DEBUG("Exit");
}
+
+void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_async_create_container_t *cb_task_data;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+ cb_task_data = &cb_data->ut.create_container;
+
+ if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
+ cb_data->id);
+
+ if (strcmp(cb_data->id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "CreateContainerInAnyContainer must be "
+ "executed on a root path");
+ goto on_error;
+ }
+
+ device = msu_device_from_path(cb_task_data->root_path,
+ upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ cb_task_data->root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ msu_device_create_container(device, client, task,
+ "DLNA.ORG_AnyContainer",
+ cb_data, cancellable);
+
+on_error:
+
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_async_update_t *cb_task_data;
+ msu_device_t *device;
+ guint32 mask;
+ gchar *root_path = NULL;
+ gchar *upnp_filter = NULL;
+ msu_task_update_t *task_data;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+ cb_task_data = &cb_data->ut.update;
+ task_data = &task->ut.update;
+
+ if (!msu_path_get_path_and_id(task->path, &root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path = %s, Id = %s", root_path, cb_data->id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s", root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (!msu_props_parse_update_filter(upnp->filter_map,
+ task_data->to_add_update,
+ task_data->to_delete,
+ &mask, &upnp_filter)) {
+ MSU_LOG_WARNING("Invalid Parameter");
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Invalid Parameter");
+ goto on_error;
+ }
+
+ cb_task_data->map = upnp->filter_map;
+
+ MSU_LOG_DEBUG("Filter = %s", upnp_filter);
+ MSU_LOG_DEBUG("Mask = 0x%x", mask);
+
+ if (mask == 0) {
+ MSU_LOG_WARNING("Empty Parameters");
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Empty Parameters");
+
+ goto on_error;
+ }
+
+ msu_device_update_object(device, client, task, cb_data, upnp_filter,
+ cancellable);
+
+on_error:
+
+ if (root_path)
+ g_free(root_path);
+
+ g_free(upnp_filter);
+
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}